Update to VS Code 1.52.1
This commit is contained in:
@ -5,3 +5,5 @@ out/**
|
||||
extension.webpack.config.js
|
||||
extension-browser.webpack.config.js
|
||||
yarn.lock
|
||||
build/**
|
||||
schemas/*.schema.src.json
|
||||
|
103
lib/vscode/extensions/configuration-editing/build/inline-allOf.ts
Executable file
103
lib/vscode/extensions/configuration-editing/build/inline-allOf.ts
Executable file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env ts-node
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Inlines "allOf"s to allow for "additionalProperties": false. (https://github.com/microsoft/vscode-remote-release/issues/2967)
|
||||
// Run this manually after updating devContainer.schema.src.json.
|
||||
|
||||
import * as fs from 'fs';
|
||||
|
||||
function transform(schema: any) {
|
||||
|
||||
const definitions = Object.keys(schema.definitions)
|
||||
.reduce((d, k) => {
|
||||
d[`#/definitions/${k}`] = (schema.definitions as any)[k];
|
||||
return d;
|
||||
}, {} as any);
|
||||
|
||||
function copy(from: any) {
|
||||
const type = Array.isArray(from) ? 'array' : typeof from;
|
||||
switch (type) {
|
||||
case 'object': {
|
||||
const to: any = {};
|
||||
for (const key in from) {
|
||||
switch (key) {
|
||||
case 'definitions':
|
||||
break;
|
||||
case 'oneOf':
|
||||
const list = copy(from[key])
|
||||
.reduce((a: any[], o: any) => {
|
||||
if (o.oneOf) {
|
||||
a.push(...o.oneOf);
|
||||
} else {
|
||||
a.push(o);
|
||||
}
|
||||
return a;
|
||||
}, [] as any[]);
|
||||
if (list.length === 1) {
|
||||
Object.assign(to, list[0]);
|
||||
} else {
|
||||
to.oneOf = list;
|
||||
}
|
||||
break;
|
||||
case 'allOf':
|
||||
const all = copy(from[key]);
|
||||
const leaves = all.map((one: any) => (one.oneOf ? one.oneOf : [one]));
|
||||
function cross(res: any, leaves: any[][]): any[] {
|
||||
if (leaves.length) {
|
||||
const rest = leaves.slice(1);
|
||||
return ([] as any[]).concat(...leaves[0].map(leaf => {
|
||||
const intermediate = { ...res, ...leaf };
|
||||
if ('properties' in res && 'properties' in leaf) {
|
||||
intermediate.properties = {
|
||||
...res.properties,
|
||||
...leaf.properties,
|
||||
};
|
||||
}
|
||||
return cross(intermediate, rest);
|
||||
}));
|
||||
}
|
||||
return [res];
|
||||
}
|
||||
const list2 = cross({}, leaves);
|
||||
if (list2.length === 1) {
|
||||
Object.assign(to, list2[0]);
|
||||
} else {
|
||||
to.oneOf = list2;
|
||||
}
|
||||
break;
|
||||
case '$ref':
|
||||
const ref = from[key];
|
||||
const definition = definitions[ref];
|
||||
if (definition) {
|
||||
Object.assign(to, copy(definition));
|
||||
} else {
|
||||
to[key] = ref;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
to[key] = copy(from[key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (to.type === 'object' && !('additionalProperties' in to)) {
|
||||
to.additionalProperties = false;
|
||||
}
|
||||
return to;
|
||||
}
|
||||
case 'array': {
|
||||
return from.map(copy);
|
||||
}
|
||||
default:
|
||||
return from;
|
||||
}
|
||||
}
|
||||
|
||||
return copy(schema);
|
||||
}
|
||||
|
||||
const devContainer = JSON.parse(fs.readFileSync('../schemas/devContainer.schema.src.json', 'utf8'));
|
||||
fs.writeFileSync('../schemas/devContainer.schema.generated.json', JSON.stringify(transform(devContainer), undefined, ' '));
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"outDir": "./out"
|
||||
}
|
||||
}
|
@ -111,11 +111,11 @@
|
||||
},
|
||||
{
|
||||
"fileMatch": "/.devcontainer/devcontainer.json",
|
||||
"url": "./schemas/devContainer.schema.json"
|
||||
"url": "./schemas/devContainer.schema.generated.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": "/.devcontainer.json",
|
||||
"url": "./schemas/devContainer.schema.json"
|
||||
"url": "./schemas/devContainer.schema.generated.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": "%APP_SETTINGS_HOME%/globalStorage/ms-vscode-remote.remote-containers/nameConfigs/*.json",
|
||||
|
@ -31,7 +31,7 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"description": "Remote environment variables."
|
||||
"description": "Remote environment variables. If these are used in the Integrated Terminal, make sure the 'Terminal > Integrated: Inherit Env' setting is enabled."
|
||||
},
|
||||
"remoteUser": {
|
||||
"type": "string",
|
||||
|
@ -0,0 +1,832 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "Defines a dev container",
|
||||
"allowComments": true,
|
||||
"allowTrailingCommas": true,
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"build": {
|
||||
"type": "object",
|
||||
"description": "Docker build-related options.",
|
||||
"properties": {
|
||||
"dockerfile": {
|
||||
"type": "string",
|
||||
"description": "The location of the Dockerfile that defines the contents of the container. The path is relative to the folder containing the `devcontainer.json` file."
|
||||
},
|
||||
"context": {
|
||||
"type": "string",
|
||||
"description": "The location of the context folder for building the Docker image. The path is relative to the folder containing the `devcontainer.json` file."
|
||||
},
|
||||
"target": {
|
||||
"type": "string",
|
||||
"description": "Target stage in a multi-stage build."
|
||||
},
|
||||
"args": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"description": "Build arguments."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"dockerfile"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"appPort": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "Application ports that are exposed by the container. This can be a single port or an array of ports. Each port can be a number or a string. A number is mapped to the same port on the host. A string is passed to Docker unchanged and can be used to map ports differently, e.g. \"8000:8010\".",
|
||||
"items": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
},
|
||||
"containerEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Container environment variables."
|
||||
},
|
||||
"containerUser": {
|
||||
"type": "string",
|
||||
"description": "The user the container will be started with. The default is the user on the Docker image."
|
||||
},
|
||||
"updateRemoteUserUID": {
|
||||
"type": "boolean",
|
||||
"description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default."
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array",
|
||||
"description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"runArgs": {
|
||||
"type": "array",
|
||||
"description": "The arguments required when starting in the container.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"shutdownAction": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"stopContainer"
|
||||
],
|
||||
"description": "Action to take when the VS Code window is closed. The default is to stop the container."
|
||||
},
|
||||
"overrideCommand": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to overwrite the command specified in the image. The default is true."
|
||||
},
|
||||
"workspaceFolder": {
|
||||
"type": "string",
|
||||
"description": "The path of the workspace folder inside the container."
|
||||
},
|
||||
"workspaceMount": {
|
||||
"type": "string",
|
||||
"description": "The --mount parameter for docker run. The default is to mount the project folder at /workspaces/$project."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A name to show for the workspace folder."
|
||||
},
|
||||
"extensions": {
|
||||
"type": "array",
|
||||
"description": "An array of extensions that should be installed into the container.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^([a-z0-9A-Z][a-z0-9\\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\\-A-Z]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$",
|
||||
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "vscode://schemas/settings/machine",
|
||||
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again."
|
||||
},
|
||||
"forwardPorts": {
|
||||
"type": "array",
|
||||
"description": "Ports that are forwarded from the container to the local machine.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"description": "Remote environment variables. If these are used in the Integrated Terminal, make sure the 'Terminal > Integrated: Inherit Env' setting is enabled."
|
||||
},
|
||||
"remoteUser": {
|
||||
"type": "string",
|
||||
"description": "The user VS Code Server will be started with. The default is the same user as the container."
|
||||
},
|
||||
"initializeCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postCreateCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postStartCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postAttachCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"devPort": {
|
||||
"type": "integer",
|
||||
"description": "The port VS Code can use to connect to its backend."
|
||||
},
|
||||
"userEnvProbe": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"loginShell",
|
||||
"loginInteractiveShell",
|
||||
"interactiveShell"
|
||||
],
|
||||
"description": "User environment probe to run. The default is none."
|
||||
},
|
||||
"codespaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Codespaces-specific configuration."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"build"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dockerFile": {
|
||||
"type": "string",
|
||||
"description": "The location of the Dockerfile that defines the contents of the container. The path is relative to the folder containing the `devcontainer.json` file."
|
||||
},
|
||||
"context": {
|
||||
"type": "string",
|
||||
"description": "The location of the context folder for building the Docker image. The path is relative to the folder containing the `devcontainer.json` file."
|
||||
},
|
||||
"build": {
|
||||
"description": "Docker build-related options.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"target": {
|
||||
"type": "string",
|
||||
"description": "Target stage in a multi-stage build."
|
||||
},
|
||||
"args": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"description": "Build arguments."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"appPort": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "Application ports that are exposed by the container. This can be a single port or an array of ports. Each port can be a number or a string. A number is mapped to the same port on the host. A string is passed to Docker unchanged and can be used to map ports differently, e.g. \"8000:8010\".",
|
||||
"items": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
},
|
||||
"containerEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Container environment variables."
|
||||
},
|
||||
"containerUser": {
|
||||
"type": "string",
|
||||
"description": "The user the container will be started with. The default is the user on the Docker image."
|
||||
},
|
||||
"updateRemoteUserUID": {
|
||||
"type": "boolean",
|
||||
"description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default."
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array",
|
||||
"description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"runArgs": {
|
||||
"type": "array",
|
||||
"description": "The arguments required when starting in the container.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"shutdownAction": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"stopContainer"
|
||||
],
|
||||
"description": "Action to take when the VS Code window is closed. The default is to stop the container."
|
||||
},
|
||||
"overrideCommand": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to overwrite the command specified in the image. The default is true."
|
||||
},
|
||||
"workspaceFolder": {
|
||||
"type": "string",
|
||||
"description": "The path of the workspace folder inside the container."
|
||||
},
|
||||
"workspaceMount": {
|
||||
"type": "string",
|
||||
"description": "The --mount parameter for docker run. The default is to mount the project folder at /workspaces/$project."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A name to show for the workspace folder."
|
||||
},
|
||||
"extensions": {
|
||||
"type": "array",
|
||||
"description": "An array of extensions that should be installed into the container.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^([a-z0-9A-Z][a-z0-9\\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\\-A-Z]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$",
|
||||
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "vscode://schemas/settings/machine",
|
||||
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again."
|
||||
},
|
||||
"forwardPorts": {
|
||||
"type": "array",
|
||||
"description": "Ports that are forwarded from the container to the local machine.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"description": "Remote environment variables. If these are used in the Integrated Terminal, make sure the 'Terminal > Integrated: Inherit Env' setting is enabled."
|
||||
},
|
||||
"remoteUser": {
|
||||
"type": "string",
|
||||
"description": "The user VS Code Server will be started with. The default is the same user as the container."
|
||||
},
|
||||
"initializeCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postCreateCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postStartCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postAttachCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"devPort": {
|
||||
"type": "integer",
|
||||
"description": "The port VS Code can use to connect to its backend."
|
||||
},
|
||||
"userEnvProbe": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"loginShell",
|
||||
"loginInteractiveShell",
|
||||
"interactiveShell"
|
||||
],
|
||||
"description": "User environment probe to run. The default is none."
|
||||
},
|
||||
"codespaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Codespaces-specific configuration."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"dockerFile"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"image": {
|
||||
"type": "string",
|
||||
"description": "The docker image that will be used to create the container."
|
||||
},
|
||||
"appPort": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "Application ports that are exposed by the container. This can be a single port or an array of ports. Each port can be a number or a string. A number is mapped to the same port on the host. A string is passed to Docker unchanged and can be used to map ports differently, e.g. \"8000:8010\".",
|
||||
"items": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
},
|
||||
"containerEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Container environment variables."
|
||||
},
|
||||
"containerUser": {
|
||||
"type": "string",
|
||||
"description": "The user the container will be started with. The default is the user on the Docker image."
|
||||
},
|
||||
"updateRemoteUserUID": {
|
||||
"type": "boolean",
|
||||
"description": "Controls whether on Linux the container's user should be updated with the local user's UID and GID. On by default."
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array",
|
||||
"description": "Mount points to set up when creating the container. See Docker's documentation for the --mount option for the supported syntax.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"runArgs": {
|
||||
"type": "array",
|
||||
"description": "The arguments required when starting in the container.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"shutdownAction": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"stopContainer"
|
||||
],
|
||||
"description": "Action to take when the VS Code window is closed. The default is to stop the container."
|
||||
},
|
||||
"overrideCommand": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to overwrite the command specified in the image. The default is true."
|
||||
},
|
||||
"workspaceFolder": {
|
||||
"type": "string",
|
||||
"description": "The path of the workspace folder inside the container."
|
||||
},
|
||||
"workspaceMount": {
|
||||
"type": "string",
|
||||
"description": "The --mount parameter for docker run. The default is to mount the project folder at /workspaces/$project."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A name to show for the workspace folder."
|
||||
},
|
||||
"extensions": {
|
||||
"type": "array",
|
||||
"description": "An array of extensions that should be installed into the container.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^([a-z0-9A-Z][a-z0-9\\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\\-A-Z]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$",
|
||||
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "vscode://schemas/settings/machine",
|
||||
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again."
|
||||
},
|
||||
"forwardPorts": {
|
||||
"type": "array",
|
||||
"description": "Ports that are forwarded from the container to the local machine.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"description": "Remote environment variables. If these are used in the Integrated Terminal, make sure the 'Terminal > Integrated: Inherit Env' setting is enabled."
|
||||
},
|
||||
"remoteUser": {
|
||||
"type": "string",
|
||||
"description": "The user VS Code Server will be started with. The default is the same user as the container."
|
||||
},
|
||||
"initializeCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postCreateCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postStartCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postAttachCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"devPort": {
|
||||
"type": "integer",
|
||||
"description": "The port VS Code can use to connect to its backend."
|
||||
},
|
||||
"userEnvProbe": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"loginShell",
|
||||
"loginInteractiveShell",
|
||||
"interactiveShell"
|
||||
],
|
||||
"description": "User environment probe to run. The default is none."
|
||||
},
|
||||
"codespaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Codespaces-specific configuration."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"image"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dockerComposeFile": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "The name of the docker-compose file(s) used to start the services.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"service": {
|
||||
"type": "string",
|
||||
"description": "The service you want to work on."
|
||||
},
|
||||
"runServices": {
|
||||
"type": "array",
|
||||
"description": "An array of services that should be started and stopped.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"workspaceFolder": {
|
||||
"type": "string",
|
||||
"description": "The path of the workspace folder inside the container. This is typically the target path of a volume mount in the docker-compose.yml."
|
||||
},
|
||||
"shutdownAction": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"stopCompose"
|
||||
],
|
||||
"description": "Action to take when the VS Code window is closed. The default is to stop the containers."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A name to show for the workspace folder."
|
||||
},
|
||||
"extensions": {
|
||||
"type": "array",
|
||||
"description": "An array of extensions that should be installed into the container.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^([a-z0-9A-Z][a-z0-9\\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\\-A-Z]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$",
|
||||
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "vscode://schemas/settings/machine",
|
||||
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again."
|
||||
},
|
||||
"forwardPorts": {
|
||||
"type": "array",
|
||||
"description": "Ports that are forwarded from the container to the local machine.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"description": "Remote environment variables. If these are used in the Integrated Terminal, make sure the 'Terminal > Integrated: Inherit Env' setting is enabled."
|
||||
},
|
||||
"remoteUser": {
|
||||
"type": "string",
|
||||
"description": "The user VS Code Server will be started with. The default is the same user as the container."
|
||||
},
|
||||
"initializeCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postCreateCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postStartCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postAttachCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"devPort": {
|
||||
"type": "integer",
|
||||
"description": "The port VS Code can use to connect to its backend."
|
||||
},
|
||||
"userEnvProbe": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"loginShell",
|
||||
"loginInteractiveShell",
|
||||
"interactiveShell"
|
||||
],
|
||||
"description": "User environment probe to run. The default is none."
|
||||
},
|
||||
"codespaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Codespaces-specific configuration."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"dockerComposeFile",
|
||||
"service",
|
||||
"workspaceFolder"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A name to show for the workspace folder."
|
||||
},
|
||||
"extensions": {
|
||||
"type": "array",
|
||||
"description": "An array of extensions that should be installed into the container.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^([a-z0-9A-Z][a-z0-9\\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\\-A-Z]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$",
|
||||
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "vscode://schemas/settings/machine",
|
||||
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again."
|
||||
},
|
||||
"forwardPorts": {
|
||||
"type": "array",
|
||||
"description": "Ports that are forwarded from the container to the local machine.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"remoteEnv": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"description": "Remote environment variables. If these are used in the Integrated Terminal, make sure the 'Terminal > Integrated: Inherit Env' setting is enabled."
|
||||
},
|
||||
"remoteUser": {
|
||||
"type": "string",
|
||||
"description": "The user VS Code Server will be started with. The default is the same user as the container."
|
||||
},
|
||||
"initializeCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postCreateCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postStartCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"postAttachCommand": {
|
||||
"type": [
|
||||
"string",
|
||||
"array"
|
||||
],
|
||||
"description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"devPort": {
|
||||
"type": "integer",
|
||||
"description": "The port VS Code can use to connect to its backend."
|
||||
},
|
||||
"userEnvProbe": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"loginShell",
|
||||
"loginInteractiveShell",
|
||||
"interactiveShell"
|
||||
],
|
||||
"description": "User environment probe to run. The default is none."
|
||||
},
|
||||
"codespaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Codespaces-specific configuration."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
"description": "Defines a dev container",
|
||||
"allowComments": true,
|
||||
"allowTrailingCommas": true,
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
"devContainerCommon": {
|
||||
"type": "object",
|
||||
@ -42,7 +41,7 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"description": "Remote environment variables."
|
||||
"description": "Remote environment variables. If these are used in the Integrated Terminal, make sure the 'Terminal > Integrated: Inherit Env' setting is enabled."
|
||||
},
|
||||
"remoteUser": {
|
||||
"type": "string",
|
||||
@ -104,6 +103,7 @@
|
||||
},
|
||||
"codespaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Codespaces-specific configuration."
|
||||
}
|
||||
}
|
@ -6,9 +6,9 @@
|
||||
|
||||
var updateGrammar = require('../../../build/npm/update-grammar');
|
||||
|
||||
updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/c.tmLanguage.json', './syntaxes/c.tmLanguage.json', undefined, 'master', 'source/languages/cpp/');
|
||||
updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/cpp.tmLanguage.json', './syntaxes/cpp.tmLanguage.json', undefined, 'master', 'source/languages/cpp/');
|
||||
updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/cpp.embedded.macro.tmLanguage.json', './syntaxes/cpp.embedded.macro.tmLanguage.json', undefined, 'master', 'source/languages/cpp/');
|
||||
updateGrammar.update('jeff-hykin/cpp-textmate-grammar', 'syntaxes/c.tmLanguage.json', './syntaxes/c.tmLanguage.json', undefined, 'master', 'source/languages/cpp/');
|
||||
updateGrammar.update('jeff-hykin/cpp-textmate-grammar', 'syntaxes/cpp.tmLanguage.json', './syntaxes/cpp.tmLanguage.json', undefined, 'master', 'source/languages/cpp/');
|
||||
updateGrammar.update('jeff-hykin/cpp-textmate-grammar', 'syntaxes/cpp.embedded.macro.tmLanguage.json', './syntaxes/cpp.embedded.macro.tmLanguage.json', undefined, 'master', 'source/languages/cpp/');
|
||||
|
||||
// `source.c.platform` which is still included by other grammars
|
||||
updateGrammar.update('textmate/c.tmbundle', 'Syntaxes/Platform.tmLanguage', './syntaxes/platform.tmLanguage.json');
|
||||
|
@ -6,11 +6,11 @@
|
||||
"git": {
|
||||
"name": "jeff-hykin/cpp-textmate-grammar",
|
||||
"repositoryUrl": "https://github.com/jeff-hykin/cpp-textmate-grammar",
|
||||
"commitHash": "666808cab3907fc91ed4d3901060ee6b045cca58"
|
||||
"commitHash": "ad9f1541fd376740c30a7257614c9cb5ed25005d"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.14.15",
|
||||
"version": "1.15.3",
|
||||
"description": "The files syntaxes/c.json and syntaxes/c++.json were derived from https://github.com/atom/language-c which was originally converted from the C TextMate bundle https://github.com/textmate/c.tmbundle."
|
||||
},
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"information_for_contributors": [
|
||||
"This file has been converted from https://github.com/jeff-hykin/cpp-textmate-grammar/blob/master//syntaxes/c.tmLanguage.json",
|
||||
"This file has been converted from https://github.com/jeff-hykin/cpp-textmate-grammar/blob/master/syntaxes/c.tmLanguage.json",
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/72b309aabb63bf14a3cdf0280149121db005d616",
|
||||
"version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/afa42b3f5529833714ae354fbc638ece8f253074",
|
||||
"name": "C",
|
||||
"scopeName": "source.c",
|
||||
"patterns": [
|
||||
@ -364,7 +364,7 @@
|
||||
{
|
||||
"name": "meta.function.c",
|
||||
"begin": "(?<!\\w)(?!\\s*(?:atomic_uint_least64_t|atomic_uint_least16_t|atomic_uint_least32_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_fast64_t|atomic_uint_fast32_t|atomic_int_least64_t|atomic_int_least32_t|pthread_rwlockattr_t|atomic_uint_fast16_t|pthread_mutexattr_t|atomic_int_fast16_t|atomic_uint_fast8_t|atomic_int_fast64_t|atomic_int_least8_t|atomic_int_fast32_t|atomic_int_fast8_t|pthread_condattr_t|pthread_rwlock_t|atomic_uintptr_t|atomic_ptrdiff_t|atomic_uintmax_t|atomic_intmax_t|atomic_char32_t|atomic_intptr_t|atomic_char16_t|pthread_mutex_t|pthread_cond_t|atomic_wchar_t|uint_least64_t|uint_least32_t|uint_least16_t|pthread_once_t|pthread_attr_t|uint_least8_t|int_least32_t|int_least16_t|pthread_key_t|uint_fast32_t|uint_fast64_t|uint_fast16_t|atomic_size_t|atomic_ushort|atomic_ullong|int_least64_t|atomic_ulong|int_least8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|memory_order|atomic_schar|atomic_uchar|atomic_short|atomic_llong|thread_local|atomic_bool|atomic_uint|atomic_long|int_fast8_t|suseconds_t|atomic_char|atomic_int|useconds_t|_Imaginary|uintmax_t|uintmax_t|in_addr_t|in_port_t|_Noreturn|blksize_t|pthread_t|uintptr_t|volatile|u_quad_t|blkcnt_t|intmax_t|intptr_t|_Complex|uint16_t|uint32_t|uint64_t|_Alignof|_Alignas|continue|unsigned|restrict|intmax_t|register|int64_t|qaddr_t|segsz_t|_Atomic|alignas|default|caddr_t|nlink_t|typedef|u_short|fixpt_t|clock_t|swblk_t|ssize_t|alignof|daddr_t|int16_t|int32_t|uint8_t|struct|mode_t|size_t|time_t|ushort|u_long|u_char|int8_t|double|signed|static|extern|inline|return|switch|xor_eq|and_eq|bitand|not_eq|sizeof|quad_t|uid_t|bitor|union|off_t|key_t|ino_t|compl|u_int|short|const|false|while|float|pid_t|break|_Bool|or_eq|div_t|dev_t|gid_t|id_t|long|case|goto|else|bool|auto|id_t|enum|uint|true|NULL|void|char|for|not|int|and|xor|do|or|if)\\s*\\()(?=[a-zA-Z_]\\w*\\s*\\()",
|
||||
"end": "(?<=\\))",
|
||||
"end": "(?!\\G)(?<=\\))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#function-innards"
|
||||
@ -464,7 +464,7 @@
|
||||
]
|
||||
},
|
||||
"backslash_escapes": {
|
||||
"match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3]\\d{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )",
|
||||
"match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3][0-7]{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )",
|
||||
"name": "constant.character.escape.c"
|
||||
},
|
||||
"block": {
|
||||
@ -690,12 +690,20 @@
|
||||
"name": "storage.type.class.doxygen.c"
|
||||
},
|
||||
{
|
||||
"match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)",
|
||||
"match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "storage.type.class.doxygen.c"
|
||||
},
|
||||
"2": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "in|out",
|
||||
"name": "keyword.other.parameter.direction.$0.c"
|
||||
}
|
||||
]
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.parameter.c"
|
||||
}
|
||||
}
|
||||
@ -768,12 +776,20 @@
|
||||
"name": "storage.type.class.doxygen.c"
|
||||
},
|
||||
{
|
||||
"match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)",
|
||||
"match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "storage.type.class.doxygen.c"
|
||||
},
|
||||
"2": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "in|out",
|
||||
"name": "keyword.other.parameter.direction.$0.c"
|
||||
}
|
||||
]
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.parameter.c"
|
||||
}
|
||||
}
|
||||
@ -859,12 +875,20 @@
|
||||
"name": "storage.type.class.doxygen.c"
|
||||
},
|
||||
{
|
||||
"match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)",
|
||||
"match": "((?<=[\\s*!\\/])[\\\\@]param)(?:\\s*\\[((?:,?\\s*(?:in|out)\\s*)+)\\])?\\s+(\\b\\w+\\b)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "storage.type.class.doxygen.c"
|
||||
},
|
||||
"2": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "in|out",
|
||||
"name": "keyword.other.parameter.direction.$0.c"
|
||||
}
|
||||
]
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.parameter.c"
|
||||
}
|
||||
}
|
||||
@ -1004,7 +1028,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"evalutation_context": {
|
||||
"evaluation_context": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#function-call-innards"
|
||||
@ -2874,95 +2898,219 @@
|
||||
},
|
||||
{
|
||||
"name": "meta.asm.c",
|
||||
"begin": "(\\b(?:__asm__|asm)\\b)\\s*((?:volatile)?)\\s*(\\()",
|
||||
"begin": "(\\b(?:__asm__|asm)\\b)\\s*((?:volatile)?)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "storage.type.asm.c"
|
||||
},
|
||||
"2": {
|
||||
"name": "storage.modifier.c"
|
||||
},
|
||||
"3": {
|
||||
"name": "punctuation.section.parens.begin.bracket.round.assembly.c"
|
||||
}
|
||||
},
|
||||
"end": "(\\))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.section.parens.end.bracket.round.assembly.c"
|
||||
}
|
||||
},
|
||||
"end": "(?!\\G)",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.quoted.double.c",
|
||||
"contentName": "meta.embedded.assembly.c",
|
||||
"begin": "(R?)(\")",
|
||||
"beginCaptures": {
|
||||
"match": "(?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:\\n|$)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "meta.encoding.c"
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#inline_comment"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.definition.string.begin.assembly.c"
|
||||
}
|
||||
},
|
||||
"end": "(\")",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.string.end.assembly.c"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "source.asm"
|
||||
"name": "comment.block.c punctuation.definition.comment.begin.c"
|
||||
},
|
||||
{
|
||||
"include": "source.x86"
|
||||
"3": {
|
||||
"name": "comment.block.c"
|
||||
},
|
||||
{
|
||||
"include": "source.x86_64"
|
||||
},
|
||||
{
|
||||
"include": "source.arm"
|
||||
},
|
||||
{
|
||||
"include": "#backslash_escapes"
|
||||
},
|
||||
{
|
||||
"include": "#string_escaped_char"
|
||||
},
|
||||
{
|
||||
"match": "(?=not)possible"
|
||||
"4": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\*\\/",
|
||||
"name": "comment.block.c punctuation.definition.comment.end.c"
|
||||
},
|
||||
{
|
||||
"match": "\\*",
|
||||
"name": "comment.block.c"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(\\()",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.section.parens.begin.bracket.round.assembly.inner.c"
|
||||
}
|
||||
},
|
||||
"end": "(\\))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.section.parens.end.bracket.round.assembly.inner.c"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#evaluation_context"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": ":",
|
||||
"name": "punctuation.separator.delimiter.colon.assembly.c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": "#comments_context"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\()",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.section.parens.begin.bracket.round.assembly.c"
|
||||
},
|
||||
"2": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#inline_comment"
|
||||
}
|
||||
]
|
||||
},
|
||||
"3": {
|
||||
"name": "comment.block.c punctuation.definition.comment.begin.c"
|
||||
},
|
||||
"4": {
|
||||
"name": "comment.block.c"
|
||||
},
|
||||
"5": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\*\\/",
|
||||
"name": "comment.block.c punctuation.definition.comment.end.c"
|
||||
},
|
||||
{
|
||||
"match": "\\*",
|
||||
"name": "comment.block.c"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"end": "(\\))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.section.parens.end.bracket.round.assembly.c"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.quoted.double.c",
|
||||
"contentName": "meta.embedded.assembly.c",
|
||||
"begin": "(R?)(\")",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "meta.encoding.c"
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.definition.string.begin.assembly.c"
|
||||
}
|
||||
},
|
||||
"end": "(\")",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.string.end.assembly.c"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "source.asm"
|
||||
},
|
||||
{
|
||||
"include": "source.x86"
|
||||
},
|
||||
{
|
||||
"include": "source.x86_64"
|
||||
},
|
||||
{
|
||||
"include": "source.arm"
|
||||
},
|
||||
{
|
||||
"include": "#backslash_escapes"
|
||||
},
|
||||
{
|
||||
"include": "#string_escaped_char"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(\\()",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.section.parens.begin.bracket.round.assembly.inner.c"
|
||||
}
|
||||
},
|
||||
"end": "(\\))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.section.parens.end.bracket.round.assembly.inner.c"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#evaluation_context"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": "\\[((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))([a-zA-Z_]\\w*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\]",
|
||||
"captures": {
|
||||
"1": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#inline_comment"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2": {
|
||||
"name": "comment.block.c punctuation.definition.comment.begin.c"
|
||||
},
|
||||
"3": {
|
||||
"name": "comment.block.c"
|
||||
},
|
||||
"4": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\*\\/",
|
||||
"name": "comment.block.c punctuation.definition.comment.end.c"
|
||||
},
|
||||
{
|
||||
"match": "\\*",
|
||||
"name": "comment.block.c"
|
||||
}
|
||||
]
|
||||
},
|
||||
"5": {
|
||||
"name": "variable.other.asm.label.c"
|
||||
},
|
||||
"6": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#inline_comment"
|
||||
}
|
||||
]
|
||||
},
|
||||
"7": {
|
||||
"name": "comment.block.c punctuation.definition.comment.begin.c"
|
||||
},
|
||||
"8": {
|
||||
"name": "comment.block.c"
|
||||
},
|
||||
"9": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\*\\/",
|
||||
"name": "comment.block.c punctuation.definition.comment.end.c"
|
||||
},
|
||||
{
|
||||
"match": "\\*",
|
||||
"name": "comment.block.c"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": ":",
|
||||
"name": "punctuation.separator.delimiter.colon.assembly.c"
|
||||
},
|
||||
{
|
||||
"include": "#comments_context"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -3194,4 +3342,4 @@
|
||||
"name": "punctuation.vararg-ellipses.c"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -298,7 +298,7 @@
|
||||
},
|
||||
{
|
||||
"c": "der",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.head.struct.cpp entity.name.type.struct.cpp",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp entity.name.type.struct.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.type: #4EC9B0",
|
||||
"light_plus": "entity.name.type: #267F99",
|
||||
@ -331,7 +331,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.head.struct.cpp",
|
||||
"r": {
|
||||
"dark_plus": "meta.preprocessor: #569CD6",
|
||||
"light_plus": "meta.preprocessor: #0000FF",
|
||||
@ -342,7 +342,7 @@
|
||||
},
|
||||
{
|
||||
"c": "public",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp storage.type.modifier.access.public.cpp",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.head.struct.cpp storage.type.modifier.access.public.cpp",
|
||||
"r": {
|
||||
"dark_plus": "storage.type: #569CD6",
|
||||
"light_plus": "storage.type: #0000FF",
|
||||
@ -353,7 +353,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.head.struct.cpp",
|
||||
"r": {
|
||||
"dark_plus": "meta.preprocessor: #569CD6",
|
||||
"light_plus": "meta.preprocessor: #0000FF",
|
||||
@ -364,7 +364,7 @@
|
||||
},
|
||||
{
|
||||
"c": "base",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.qualified_type.cpp entity.name.type.cpp",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.head.struct.cpp meta.qualified_type.cpp entity.name.type.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.type: #4EC9B0",
|
||||
"light_plus": "entity.name.type: #267F99",
|
||||
@ -375,7 +375,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.head.struct.cpp",
|
||||
"r": {
|
||||
"dark_plus": "meta.preprocessor: #569CD6",
|
||||
"light_plus": "meta.preprocessor: #0000FF",
|
||||
@ -386,7 +386,7 @@
|
||||
},
|
||||
{
|
||||
"c": "\\",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp constant.character.escape.line-continuation.cpp",
|
||||
"t": "source.cpp meta.preprocessor.macro.cpp meta.block.namespace.cpp meta.body.namespace.cpp meta.block.struct.cpp meta.head.struct.cpp constant.character.escape.line-continuation.cpp",
|
||||
"r": {
|
||||
"dark_plus": "constant.character.escape: #D7BA7D",
|
||||
"light_plus": "constant.character.escape: #EE0000",
|
||||
|
@ -23,7 +23,7 @@
|
||||
},
|
||||
{
|
||||
"c": "Foo",
|
||||
"t": "source.cpp meta.block.struct.cpp meta.head.struct.cpp entity.name.type.struct.cpp",
|
||||
"t": "source.cpp meta.block.struct.cpp entity.name.type.struct.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.type: #4EC9B0",
|
||||
"light_plus": "entity.name.type: #267F99",
|
||||
@ -34,7 +34,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.block.struct.cpp meta.head.struct.cpp",
|
||||
"t": "source.cpp meta.block.struct.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -265,18 +265,18 @@
|
||||
},
|
||||
{
|
||||
"c": "Foo",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp entity.name.type.constructor.cpp",
|
||||
"t": "source.cpp entity.name.scope-resolution.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.type: #4EC9B0",
|
||||
"light_plus": "entity.name.type: #267F99",
|
||||
"dark_plus": "entity.name.scope-resolution: #4EC9B0",
|
||||
"light_plus": "entity.name.scope-resolution: #267F99",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "entity.name.type: #4EC9B0"
|
||||
"hc_black": "entity.name.scope-resolution: #4EC9B0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "::",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.constructor.cpp",
|
||||
"t": "source.cpp punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -287,7 +287,7 @@
|
||||
},
|
||||
{
|
||||
"c": "Foo",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp entity.name.function.definition.special.constructor.cpp",
|
||||
"t": "source.cpp entity.name.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.function: #DCDCAA",
|
||||
"light_plus": "entity.name.function: #795E26",
|
||||
@ -298,7 +298,7 @@
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.section.parameters.begin.bracket.round.special.constructor.cpp",
|
||||
"t": "source.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -309,7 +309,7 @@
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.section.parameters.end.bracket.round.special.constructor.cpp",
|
||||
"t": "source.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -319,30 +319,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ":",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.separator.initializers.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp",
|
||||
"c": " : ",
|
||||
"t": "source.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -353,7 +331,7 @@
|
||||
},
|
||||
{
|
||||
"c": "a",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp entity.name.function.call.initializer.cpp",
|
||||
"t": "source.cpp entity.name.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.function: #DCDCAA",
|
||||
"light_plus": "entity.name.function: #795E26",
|
||||
@ -364,7 +342,7 @@
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp",
|
||||
"t": "source.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -375,7 +353,7 @@
|
||||
},
|
||||
{
|
||||
"c": "1",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp meta.parameter.initialization.cpp constant.numeric.decimal.cpp",
|
||||
"t": "source.cpp constant.numeric.decimal.cpp",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #098658",
|
||||
@ -386,7 +364,7 @@
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp",
|
||||
"t": "source.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -397,7 +375,7 @@
|
||||
},
|
||||
{
|
||||
"c": ",",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.separator.delimiter.comma.cpp",
|
||||
"t": "source.cpp punctuation.separator.delimiter.comma.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -408,7 +386,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp comment.line.double-slash.cpp",
|
||||
"t": "source.cpp comment.line.double-slash.cpp",
|
||||
"r": {
|
||||
"dark_plus": "comment: #6A9955",
|
||||
"light_plus": "comment: #008000",
|
||||
@ -419,7 +397,7 @@
|
||||
},
|
||||
{
|
||||
"c": "//",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp",
|
||||
"t": "source.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp",
|
||||
"r": {
|
||||
"dark_plus": "comment: #6A9955",
|
||||
"light_plus": "comment: #008000",
|
||||
@ -430,7 +408,7 @@
|
||||
},
|
||||
{
|
||||
"c": " b(2),",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp comment.line.double-slash.cpp",
|
||||
"t": "source.cpp comment.line.double-slash.cpp",
|
||||
"r": {
|
||||
"dark_plus": "comment: #6A9955",
|
||||
"light_plus": "comment: #008000",
|
||||
@ -441,7 +419,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp",
|
||||
"t": "source.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -452,7 +430,7 @@
|
||||
},
|
||||
{
|
||||
"c": "c",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp entity.name.function.call.initializer.cpp",
|
||||
"t": "source.cpp entity.name.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.function: #DCDCAA",
|
||||
"light_plus": "entity.name.function: #795E26",
|
||||
@ -463,7 +441,7 @@
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp",
|
||||
"t": "source.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -474,7 +452,7 @@
|
||||
},
|
||||
{
|
||||
"c": "3",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp meta.parameter.initialization.cpp constant.numeric.decimal.cpp",
|
||||
"t": "source.cpp constant.numeric.decimal.cpp",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #098658",
|
||||
@ -485,7 +463,7 @@
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp",
|
||||
"t": "source.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -496,7 +474,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp",
|
||||
"t": "source.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -507,7 +485,7 @@
|
||||
},
|
||||
{
|
||||
"c": "{",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.head.function.definition.special.constructor.cpp punctuation.section.block.begin.bracket.curly.function.definition.special.constructor.cpp",
|
||||
"t": "source.cpp meta.block.cpp punctuation.section.block.begin.bracket.curly.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -518,7 +496,7 @@
|
||||
},
|
||||
{
|
||||
"c": "}",
|
||||
"t": "source.cpp meta.function.definition.special.constructor.cpp meta.body.function.definition.special.constructor.cpp punctuation.section.block.end.bracket.curly.function.definition.special.constructor.cpp",
|
||||
"t": "source.cpp meta.block.cpp punctuation.section.block.end.bracket.curly.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -527,4 +505,4 @@
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
File diff suppressed because it is too large
Load Diff
@ -122,7 +122,7 @@
|
||||
},
|
||||
{
|
||||
"c": "%d",
|
||||
"t": "source.cpp string.quoted.double.cpp constant.other.placeholder.cpp",
|
||||
"t": "source.cpp string.quoted.double.cpp constant.other.placeholder",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
@ -430,7 +430,7 @@
|
||||
},
|
||||
{
|
||||
"c": "%d",
|
||||
"t": "source.cpp string.quoted.double.cpp constant.other.placeholder.cpp",
|
||||
"t": "source.cpp string.quoted.double.cpp constant.other.placeholder",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
@ -474,7 +474,7 @@
|
||||
},
|
||||
{
|
||||
"c": "user_candidate",
|
||||
"t": "source.cpp meta.bracket.square.access.cpp variable.other.object.cpp",
|
||||
"t": "source.cpp meta.bracket.square.access variable.other.object",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
@ -485,7 +485,7 @@
|
||||
},
|
||||
{
|
||||
"c": "[",
|
||||
"t": "source.cpp meta.bracket.square.access.cpp punctuation.definition.begin.bracket.square.cpp",
|
||||
"t": "source.cpp meta.bracket.square.access punctuation.definition.begin.bracket.square",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -496,7 +496,7 @@
|
||||
},
|
||||
{
|
||||
"c": "i",
|
||||
"t": "source.cpp meta.bracket.square.access.cpp",
|
||||
"t": "source.cpp meta.bracket.square.access",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -507,7 +507,7 @@
|
||||
},
|
||||
{
|
||||
"c": "]",
|
||||
"t": "source.cpp meta.bracket.square.access.cpp punctuation.definition.end.bracket.square.cpp",
|
||||
"t": "source.cpp meta.bracket.square.access punctuation.definition.end.bracket.square",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -727,7 +727,7 @@
|
||||
},
|
||||
{
|
||||
"c": "O",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp entity.name.type.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp entity.name.type.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.type: #4EC9B0",
|
||||
"light_plus": "entity.name.type: #267F99",
|
||||
@ -738,7 +738,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -749,7 +749,7 @@
|
||||
},
|
||||
{
|
||||
"c": "obj",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp variable.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
@ -1464,7 +1464,7 @@
|
||||
},
|
||||
{
|
||||
"c": "%s",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp constant.other.placeholder.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp constant.other.placeholder",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
@ -1486,7 +1486,7 @@
|
||||
},
|
||||
{
|
||||
"c": "%s",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp constant.other.placeholder.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp constant.other.placeholder",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
@ -1805,7 +1805,7 @@
|
||||
},
|
||||
{
|
||||
"c": "movw $0x38, %ax; ltr %ax",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp string.quoted.double.cpp meta.embedded.assembly.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp string.quoted.double.cpp meta.embedded.assembly",
|
||||
"r": {
|
||||
"dark_plus": "meta.embedded.assembly: #CE9178",
|
||||
"light_plus": "meta.embedded.assembly: #A31515",
|
||||
@ -1979,4 +1979,4 @@
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
@ -287,7 +287,7 @@
|
||||
},
|
||||
{
|
||||
"c": "Rectangle",
|
||||
"t": "source.cpp meta.block.class.cpp meta.head.class.cpp entity.name.type.class.cpp",
|
||||
"t": "source.cpp meta.block.class.cpp entity.name.type.class.cpp",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.type: #4EC9B0",
|
||||
"light_plus": "entity.name.type: #267F99",
|
||||
@ -298,7 +298,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.block.class.cpp meta.head.class.cpp",
|
||||
"t": "source.cpp meta.block.class.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -485,7 +485,7 @@
|
||||
},
|
||||
{
|
||||
"c": "int",
|
||||
"t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"r": {
|
||||
"dark_plus": "storage.type: #569CD6",
|
||||
"light_plus": "storage.type: #0000FF",
|
||||
@ -496,7 +496,7 @@
|
||||
},
|
||||
{
|
||||
"c": ",",
|
||||
"t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp punctuation.separator.delimiter.comma.cpp",
|
||||
"t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp punctuation.separator.delimiter.comma.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -507,7 +507,7 @@
|
||||
},
|
||||
{
|
||||
"c": "int",
|
||||
"t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"r": {
|
||||
"dark_plus": "storage.type: #569CD6",
|
||||
"light_plus": "storage.type: #0000FF",
|
||||
@ -793,7 +793,7 @@
|
||||
},
|
||||
{
|
||||
"c": "int",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"r": {
|
||||
"dark_plus": "storage.type: #569CD6",
|
||||
"light_plus": "storage.type: #0000FF",
|
||||
@ -804,7 +804,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -815,7 +815,7 @@
|
||||
},
|
||||
{
|
||||
"c": "x",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp variable.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
@ -826,7 +826,7 @@
|
||||
},
|
||||
{
|
||||
"c": ",",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp punctuation.separator.delimiter.comma.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp punctuation.separator.delimiter.comma.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -837,7 +837,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -848,7 +848,7 @@
|
||||
},
|
||||
{
|
||||
"c": "int",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"r": {
|
||||
"dark_plus": "storage.type: #569CD6",
|
||||
"light_plus": "storage.type: #0000FF",
|
||||
@ -859,7 +859,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -870,7 +870,7 @@
|
||||
},
|
||||
{
|
||||
"c": "y",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters meta.parameter.cpp variable.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
@ -1123,7 +1123,7 @@
|
||||
},
|
||||
{
|
||||
"c": "long",
|
||||
"t": "source.cpp meta.function.definition.special.operator-overload.cpp meta.head.function.definition.special.operator-overload.cpp meta.function.definition.parameters.special.operator-overload.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"t": "source.cpp meta.function.definition.special.operator-overload.cpp meta.head.function.definition.special.operator-overload.cpp meta.function.definition.parameters.special.operator-overload meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"r": {
|
||||
"dark_plus": "storage.type: #569CD6",
|
||||
"light_plus": "storage.type: #0000FF",
|
||||
@ -1134,7 +1134,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.cpp meta.function.definition.special.operator-overload.cpp meta.head.function.definition.special.operator-overload.cpp meta.function.definition.parameters.special.operator-overload.cpp meta.parameter.cpp",
|
||||
"t": "source.cpp meta.function.definition.special.operator-overload.cpp meta.head.function.definition.special.operator-overload.cpp meta.function.definition.parameters.special.operator-overload meta.parameter.cpp",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@ -1145,7 +1145,7 @@
|
||||
},
|
||||
{
|
||||
"c": "double",
|
||||
"t": "source.cpp meta.function.definition.special.operator-overload.cpp meta.head.function.definition.special.operator-overload.cpp meta.function.definition.parameters.special.operator-overload.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"t": "source.cpp meta.function.definition.special.operator-overload.cpp meta.head.function.definition.special.operator-overload.cpp meta.function.definition.parameters.special.operator-overload meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp",
|
||||
"r": {
|
||||
"dark_plus": "storage.type: #569CD6",
|
||||
"light_plus": "storage.type: #0000FF",
|
||||
@ -1519,7 +1519,7 @@
|
||||
},
|
||||
{
|
||||
"c": "movl %a %b",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp string.quoted.double.cpp meta.embedded.assembly.cpp",
|
||||
"t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp string.quoted.double.cpp meta.embedded.assembly",
|
||||
"r": {
|
||||
"dark_plus": "meta.embedded.assembly: #CE9178",
|
||||
"light_plus": "meta.embedded.assembly: #A31515",
|
||||
|
@ -1,14 +1,5 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Debug Extension and Language Server",
|
||||
"configurations": [
|
||||
"Launch Extension",
|
||||
"Attach Language Server"
|
||||
]
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
@ -41,19 +32,6 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Attach Language Server",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"protocol": "inspector",
|
||||
"port": 6044,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/server/out/**/*.js"
|
||||
],
|
||||
"smartStep": true,
|
||||
"restart": true
|
||||
},
|
||||
{
|
||||
"name": "Server Unit Tests",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
@ -74,4 +52,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,13 @@ import { TextDecoder } from 'util';
|
||||
|
||||
// this method is called when vs code is activated
|
||||
export function activate(context: ExtensionContext) {
|
||||
|
||||
const clientMain = extensions.getExtension('vscode.css-language-features')?.packageJSON?.main || '';
|
||||
|
||||
const serverMain = `./server/${clientMain.indexOf('/dist/') !== -1 ? 'dist' : 'out'}/node/cssServerMain`;
|
||||
const serverModule = context.asAbsolutePath(serverMain);
|
||||
|
||||
// The debug options for the server
|
||||
const debugOptions = { execArgv: ['--nolazy', '--inspect=6044'] };
|
||||
const debugOptions = { execArgv: ['--nolazy', '--inspect=' + (7000 + Math.round(Math.random() * 999))] };
|
||||
|
||||
// If the extension is launch in debug mode the debug server options are use
|
||||
// Otherwise the run options are used
|
||||
|
@ -10,7 +10,7 @@
|
||||
"main": "./out/node/cssServerMain",
|
||||
"browser": "./dist/browser/cssServerMain",
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^4.3.5",
|
||||
"vscode-css-languageservice": "^4.4.0",
|
||||
"vscode-languageserver": "7.0.0-next.3",
|
||||
"vscode-uri": "^2.1.2"
|
||||
},
|
||||
|
@ -90,7 +90,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
||||
|
||||
const capabilities: ServerCapabilities = {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
completionProvider: snippetSupport ? { resolveProvider: false, triggerCharacters: ['/', '-'] } : undefined,
|
||||
completionProvider: snippetSupport ? { resolveProvider: false, triggerCharacters: ['/', '-', ':'] } : undefined,
|
||||
hoverProvider: true,
|
||||
documentSymbolProvider: true,
|
||||
referencesProvider: true,
|
||||
|
@ -696,10 +696,10 @@ to-regex-range@^5.0.1:
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
vscode-css-languageservice@^4.3.5:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.3.5.tgz#92f8817057dee7c381df2289aad539c7b553548a"
|
||||
integrity sha512-g9Pjxt9T32jhY0nTOo7WRFm0As27IfdaAxcFa8c7Rml1ZqBn3XXbkExjzxY7sBWYm7I1Tp4dK6UHXHoUQHGwig==
|
||||
vscode-css-languageservice@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.4.0.tgz#a7c5edf3057e707601ca18fa3728784a298513b4"
|
||||
integrity sha512-jWi+297PJUUWTHwlcrZz0zIuEXuHOBJIQMapXmEzbosWGv/gMnNSAMV4hTKnl5wzxvZKZzV6j+WFdrSlKQ5qnw==
|
||||
dependencies:
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "3.16.0-next.2"
|
||||
|
@ -9,9 +9,13 @@ import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
const TEXT_ALWAYS = localize('status.text.auto.attach.always', 'Auto Attach: Always');
|
||||
const TEXT_SMART = localize('status.text.auto.attach.smart', 'Auto Attach: Smart');
|
||||
const TEXT_WITH_FLAG = localize('status.text.auto.attach.withFlag', 'Auto Attach: With Flag');
|
||||
const TEXT_STATUSBAR_LABEL = {
|
||||
[State.Disabled]: localize('status.text.auto.attach.disabled', 'Auto Attach: Disabled'),
|
||||
[State.Always]: localize('status.text.auto.attach.always', 'Auto Attach: Always'),
|
||||
[State.Smart]: localize('status.text.auto.attach.smart', 'Auto Attach: Smart'),
|
||||
[State.OnlyWithFlag]: localize('status.text.auto.attach.withFlag', 'Auto Attach: With Flag'),
|
||||
};
|
||||
|
||||
const TEXT_STATE_LABEL = {
|
||||
[State.Disabled]: localize('debug.javascript.autoAttach.disabled.label', 'Disabled'),
|
||||
[State.Always]: localize('debug.javascript.autoAttach.always.label', 'Always'),
|
||||
@ -41,6 +45,9 @@ const TEXT_STATE_DESCRIPTION = {
|
||||
};
|
||||
const TEXT_TOGGLE_WORKSPACE = localize('scope.workspace', 'Toggle auto attach in this workspace');
|
||||
const TEXT_TOGGLE_GLOBAL = localize('scope.global', 'Toggle auto attach on this machine');
|
||||
const TEXT_TEMP_DISABLE = localize('tempDisable.disable', 'Temporarily disable auto attach in this session');
|
||||
const TEXT_TEMP_ENABLE = localize('tempDisable.enable', 'Re-enable auto attach');
|
||||
const TEXT_TEMP_DISABLE_LABEL = localize('tempDisable.suffix', 'Auto Attach: Disabled');
|
||||
|
||||
const TOGGLE_COMMAND = 'extension.node-debug.toggleAutoAttach';
|
||||
const STORAGE_IPC = 'jsDebugIpcState';
|
||||
@ -65,12 +72,13 @@ const enum State {
|
||||
let currentState: Promise<{ context: vscode.ExtensionContext; state: State | null }>;
|
||||
let statusItem: vscode.StatusBarItem | undefined; // and there is no status bar item
|
||||
let server: Promise<Server | undefined> | undefined; // auto attach server
|
||||
let isTemporarilyDisabled = false; // whether the auto attach server is disabled temporarily, reset whenever the state changes
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
currentState = Promise.resolve({ context, state: null });
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand(TOGGLE_COMMAND, toggleAutoAttachSetting),
|
||||
vscode.commands.registerCommand(TOGGLE_COMMAND, toggleAutoAttachSetting.bind(null, context)),
|
||||
);
|
||||
|
||||
context.subscriptions.push(
|
||||
@ -108,24 +116,36 @@ function getDefaultScope(info: ReturnType<vscode.WorkspaceConfiguration['inspect
|
||||
return vscode.ConfigurationTarget.Global;
|
||||
}
|
||||
|
||||
type PickResult = { state: State } | { scope: vscode.ConfigurationTarget } | undefined;
|
||||
type PickResult = { state: State } | { setTempDisabled: boolean } | { scope: vscode.ConfigurationTarget } | undefined;
|
||||
type PickItem = vscode.QuickPickItem & ({ state: State } | { setTempDisabled: boolean });
|
||||
|
||||
async function toggleAutoAttachSetting(scope?: vscode.ConfigurationTarget): Promise<void> {
|
||||
async function toggleAutoAttachSetting(context: vscode.ExtensionContext, scope?: vscode.ConfigurationTarget): Promise<void> {
|
||||
const section = vscode.workspace.getConfiguration(SETTING_SECTION);
|
||||
scope = scope || getDefaultScope(section.inspect(SETTING_STATE));
|
||||
|
||||
const isGlobalScope = scope === vscode.ConfigurationTarget.Global;
|
||||
const quickPick = vscode.window.createQuickPick<vscode.QuickPickItem & { state: State }>();
|
||||
const quickPick = vscode.window.createQuickPick<PickItem>();
|
||||
const current = readCurrentState();
|
||||
|
||||
quickPick.items = [State.Always, State.Smart, State.OnlyWithFlag, State.Disabled].map(state => ({
|
||||
const items: PickItem[] = [State.Always, State.Smart, State.OnlyWithFlag, State.Disabled].map(state => ({
|
||||
state,
|
||||
label: TEXT_STATE_LABEL[state],
|
||||
description: TEXT_STATE_DESCRIPTION[state],
|
||||
alwaysShow: true,
|
||||
}));
|
||||
|
||||
quickPick.activeItems = quickPick.items.filter(i => i.state === current);
|
||||
if (current !== State.Disabled) {
|
||||
items.unshift({
|
||||
setTempDisabled: !isTemporarilyDisabled,
|
||||
label: isTemporarilyDisabled ? TEXT_TEMP_ENABLE : TEXT_TEMP_DISABLE,
|
||||
alwaysShow: true,
|
||||
});
|
||||
}
|
||||
|
||||
quickPick.items = items;
|
||||
quickPick.activeItems = isTemporarilyDisabled
|
||||
? [items[0]]
|
||||
: quickPick.items.filter(i => 'state' in i && i.state === current);
|
||||
quickPick.title = isGlobalScope ? TEXT_TOGGLE_GLOBAL : TEXT_TOGGLE_WORKSPACE;
|
||||
quickPick.buttons = [
|
||||
{
|
||||
@ -136,7 +156,7 @@ async function toggleAutoAttachSetting(scope?: vscode.ConfigurationTarget): Prom
|
||||
|
||||
quickPick.show();
|
||||
|
||||
const result = await new Promise<PickResult>(resolve => {
|
||||
let result = await new Promise<PickResult>(resolve => {
|
||||
quickPick.onDidAccept(() => resolve(quickPick.selectedItems[0]));
|
||||
quickPick.onDidHide(() => resolve(undefined));
|
||||
quickPick.onDidTriggerButton(() => {
|
||||
@ -155,11 +175,26 @@ async function toggleAutoAttachSetting(scope?: vscode.ConfigurationTarget): Prom
|
||||
}
|
||||
|
||||
if ('scope' in result) {
|
||||
return await toggleAutoAttachSetting(result.scope);
|
||||
return await toggleAutoAttachSetting(context, result.scope);
|
||||
}
|
||||
|
||||
if ('state' in result) {
|
||||
section.update(SETTING_STATE, result.state, scope);
|
||||
if (result.state !== current) {
|
||||
section.update(SETTING_STATE, result.state, scope);
|
||||
} else if (isTemporarilyDisabled) {
|
||||
result = { setTempDisabled: false };
|
||||
}
|
||||
}
|
||||
|
||||
if ('setTempDisabled' in result) {
|
||||
updateStatusBar(context, current, true);
|
||||
isTemporarilyDisabled = result.setTempDisabled;
|
||||
if (result.setTempDisabled) {
|
||||
await destroyAttachServer();
|
||||
} else {
|
||||
await createAttachServer(context); // unsets temp disabled var internally
|
||||
}
|
||||
updateStatusBar(context, current, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,26 +203,6 @@ function readCurrentState(): State {
|
||||
return section.get<State>(SETTING_STATE) ?? State.Disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the status bar exists and is visible.
|
||||
*/
|
||||
function ensureStatusBarExists(context: vscode.ExtensionContext) {
|
||||
if (!statusItem) {
|
||||
statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||
statusItem.command = TOGGLE_COMMAND;
|
||||
statusItem.tooltip = localize(
|
||||
'status.tooltip.auto.attach',
|
||||
'Automatically attach to node.js processes in debug mode',
|
||||
);
|
||||
statusItem.show();
|
||||
context.subscriptions.push(statusItem);
|
||||
} else {
|
||||
statusItem.show();
|
||||
}
|
||||
|
||||
return statusItem;
|
||||
}
|
||||
|
||||
async function clearJsDebugAttachState(context: vscode.ExtensionContext) {
|
||||
await context.workspaceState.update(STORAGE_IPC, undefined);
|
||||
await vscode.commands.executeCommand('extension.js-debug.clearAutoAttachVariables');
|
||||
@ -275,28 +290,46 @@ interface CachedIpcState {
|
||||
const transitions: { [S in State]: (context: vscode.ExtensionContext) => Promise<void> } = {
|
||||
async [State.Disabled](context) {
|
||||
await clearJsDebugAttachState(context);
|
||||
statusItem?.hide();
|
||||
},
|
||||
|
||||
async [State.OnlyWithFlag](context) {
|
||||
await createAttachServer(context);
|
||||
const statusItem = ensureStatusBarExists(context);
|
||||
statusItem.text = TEXT_WITH_FLAG;
|
||||
},
|
||||
|
||||
async [State.Smart](context) {
|
||||
await createAttachServer(context);
|
||||
const statusItem = ensureStatusBarExists(context);
|
||||
statusItem.text = TEXT_SMART;
|
||||
},
|
||||
|
||||
async [State.Always](context) {
|
||||
await createAttachServer(context);
|
||||
const statusItem = ensureStatusBarExists(context);
|
||||
statusItem.text = TEXT_ALWAYS;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures the status bar text reflects the current state.
|
||||
*/
|
||||
function updateStatusBar(context: vscode.ExtensionContext, state: State, busy = false) {
|
||||
if (state === State.Disabled && !busy) {
|
||||
statusItem?.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!statusItem) {
|
||||
statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||
statusItem.command = TOGGLE_COMMAND;
|
||||
statusItem.tooltip = localize(
|
||||
'status.tooltip.auto.attach',
|
||||
'Automatically attach to node.js processes in debug mode',
|
||||
);
|
||||
context.subscriptions.push(statusItem);
|
||||
}
|
||||
|
||||
let text = busy ? '$(loading) ' : '';
|
||||
text += isTemporarilyDisabled ? TEXT_TEMP_DISABLE_LABEL : TEXT_STATUSBAR_LABEL[state];
|
||||
statusItem.text = text;
|
||||
statusItem.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the auto attach feature based on the user or workspace setting
|
||||
*/
|
||||
@ -306,7 +339,13 @@ function updateAutoAttach(newState: State) {
|
||||
return { context, state: oldState };
|
||||
}
|
||||
|
||||
if (oldState !== null) {
|
||||
updateStatusBar(context, oldState, true);
|
||||
}
|
||||
|
||||
await transitions[newState](context);
|
||||
isTemporarilyDisabled = false;
|
||||
updateStatusBar(context, newState, false);
|
||||
return { context, state: newState };
|
||||
});
|
||||
}
|
||||
|
@ -39,8 +39,7 @@
|
||||
"openExternally"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%debug.server.ready.action.openExternally.description%",
|
||||
"%debug.server.ready.action.debugWithChrome.description%"
|
||||
"%debug.server.ready.action.openExternally.description%"
|
||||
],
|
||||
"markdownDescription": "%debug.server.ready.action.description%",
|
||||
"default": "openExternally"
|
||||
@ -71,7 +70,6 @@
|
||||
"debugWithChrome"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%debug.server.ready.action.openExternally.description%",
|
||||
"%debug.server.ready.action.debugWithChrome.description%"
|
||||
],
|
||||
"markdownDescription": "%debug.server.ready.action.description%",
|
||||
@ -93,6 +91,39 @@
|
||||
"default": "${workspaceFolder}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"markdownDescription": "%debug.server.ready.serverReadyAction.description%",
|
||||
"default": {
|
||||
"action": "startDebugging",
|
||||
"name": "<launch browser config name>"
|
||||
},
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"startDebugging"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%debug.server.ready.action.startDebugging.description%"
|
||||
],
|
||||
"markdownDescription": "%debug.server.ready.action.description%",
|
||||
"default": "startDebugging"
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"markdownDescription": "%debug.server.ready.pattern.description%",
|
||||
"default": "listening on port ([0-9]+)"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"markdownDescription": "%debug.server.ready.debugConfigName.description%",
|
||||
"default": "Launch Browser"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
"debug.server.ready.action.description": "What to do with the URI when the server is ready.",
|
||||
"debug.server.ready.action.openExternally.description": "Open URI externally with the default application.",
|
||||
"debug.server.ready.action.debugWithChrome.description": "Start debugging with the 'Debugger for Chrome'.",
|
||||
"debug.server.ready.action.startDebugging.description": "Run another launch configuration.",
|
||||
"debug.server.ready.pattern.description": "Server is ready if this pattern appears on the debug console. The first capture group must include a URI or a port number.",
|
||||
"debug.server.ready.uriFormat.description": "A format string used when constructing the URI from a port number. The first '%s' is substituted with the port number.",
|
||||
"debug.server.ready.webRoot.description": "Value passed to the debug configuration for the 'Debugger for Chrome'."
|
||||
"debug.server.ready.webRoot.description": "Value passed to the debug configuration for the 'Debugger for Chrome'.",
|
||||
"debug.server.ready.debugConfigName.description": "Name of the launch configuration to run."
|
||||
}
|
||||
|
@ -16,9 +16,10 @@ const WEB_ROOT = '${workspaceFolder}';
|
||||
|
||||
interface ServerReadyAction {
|
||||
pattern: string;
|
||||
action?: 'openExternally' | 'debugWithChrome';
|
||||
action?: 'openExternally' | 'debugWithChrome' | 'startDebugging';
|
||||
uriFormat?: string;
|
||||
webRoot?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
class ServerReadyDetector extends vscode.Disposable {
|
||||
@ -155,6 +156,10 @@ class ServerReadyDetector extends vscode.Disposable {
|
||||
});
|
||||
break;
|
||||
|
||||
case 'startDebugging':
|
||||
vscode.debug.startDebugging(session.workspaceFolder, args.name || 'unspecified');
|
||||
break;
|
||||
|
||||
default:
|
||||
// not supported
|
||||
break;
|
||||
|
@ -342,6 +342,11 @@
|
||||
"command": "editor.emmet.action.reflectCSSValue",
|
||||
"title": "%command.reflectCSSValue%",
|
||||
"category": "Emmet"
|
||||
},
|
||||
{
|
||||
"command": "workbench.action.showEmmetCommands",
|
||||
"title": "%command.showEmmetCommands%",
|
||||
"category": ""
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
@ -433,7 +438,7 @@
|
||||
"dependencies": {
|
||||
"@emmetio/css-parser": "ramya-rao-a/css-parser#vscode",
|
||||
"@emmetio/html-matcher": "^0.3.3",
|
||||
"@emmetio/math-expression": "^0.1.1",
|
||||
"@emmetio/math-expression": "^1.0.4",
|
||||
"image-size": "^0.5.2",
|
||||
"vscode-emmet-helper": "~2.0.0",
|
||||
"vscode-html-languageservice": "^3.0.3"
|
||||
|
@ -23,6 +23,7 @@
|
||||
"command.decrementNumberByOneTenth": "Decrement by 0.1",
|
||||
"command.incrementNumberByTen": "Increment by 10",
|
||||
"command.decrementNumberByTen": "Decrement by 10",
|
||||
"command.showEmmetCommands": "Show Emmet Commands",
|
||||
"emmetSyntaxProfiles": "Define profile for specified syntax or use your own profile with specific rules.",
|
||||
"emmetExclude": "An array of languages where Emmet abbreviations should not be expanded.",
|
||||
"emmetExtensionsPath": "Path to a folder containing Emmet profiles and snippets.",
|
||||
|
@ -138,6 +138,7 @@ function doWrapping(individualLines: boolean, args: any) {
|
||||
newText = newText.replace(/\$\{[\d]*(:[^}]*)?\}/g, (match) => { // Replacing Placeholders
|
||||
return match.replace(/^\$\{[\d]*:/, '').replace('}', '');
|
||||
});
|
||||
newText = newText.replace(/\\\$/g, '$'); // Remove backslashes before $
|
||||
builder.replace(oldPreviewRange, newText);
|
||||
|
||||
const expandedTextLines = newText.split('\n');
|
||||
|
@ -124,6 +124,10 @@ export function activateEmmetExtension(context: vscode.ExtensionContext) {
|
||||
return reflectCssValue();
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('workbench.action.showEmmetCommands', () => {
|
||||
vscode.commands.executeCommand('workbench.action.quickOpen', '>Emmet: ');
|
||||
}));
|
||||
|
||||
updateEmmetExtensionsPath();
|
||||
|
||||
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
|
||||
|
@ -6,24 +6,42 @@
|
||||
/* Based on @sergeche's work in his emmet plugin */
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import evaluate from '@emmetio/math-expression';
|
||||
import evaluate, { extract } from '@emmetio/math-expression';
|
||||
import { DocumentStreamReader } from './bufferStream';
|
||||
|
||||
export function evaluateMathExpression() {
|
||||
export function evaluateMathExpression(): Thenable<boolean> {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
vscode.window.showInformationMessage('No editor is active');
|
||||
return;
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
const stream = new DocumentStreamReader(editor.document);
|
||||
editor.edit(editBuilder => {
|
||||
return editor.edit(editBuilder => {
|
||||
editor.selections.forEach(selection => {
|
||||
const pos = selection.isReversed ? selection.anchor : selection.active;
|
||||
stream.pos = pos;
|
||||
// startpos always comes before endpos
|
||||
const startpos = selection.isReversed ? selection.active : selection.anchor;
|
||||
const endpos = selection.isReversed ? selection.anchor : selection.active;
|
||||
const selectionText = stream.substring(startpos, endpos);
|
||||
|
||||
try {
|
||||
const result = String(evaluate(stream, true));
|
||||
editBuilder.replace(new vscode.Range(stream.pos, pos), result);
|
||||
if (selectionText) {
|
||||
// respect selections
|
||||
const result = String(evaluate(selectionText));
|
||||
editBuilder.replace(new vscode.Range(startpos, endpos), result);
|
||||
} else {
|
||||
// no selection made, extract expression from line
|
||||
const lineToSelectionEnd = stream.substring(new vscode.Position(selection.end.line, 0), endpos);
|
||||
const extractedIndices = extract(lineToSelectionEnd);
|
||||
if (!extractedIndices) {
|
||||
throw new Error('Invalid extracted indices');
|
||||
}
|
||||
const result = String(evaluate(lineToSelectionEnd.substr(extractedIndices[0], extractedIndices[1])));
|
||||
const rangeToReplace = new vscode.Range(
|
||||
new vscode.Position(selection.end.line, extractedIndices[0]),
|
||||
new vscode.Position(selection.end.line, extractedIndices[1])
|
||||
);
|
||||
editBuilder.replace(rangeToReplace, result);
|
||||
}
|
||||
} catch (err) {
|
||||
vscode.window.showErrorMessage('Could not evaluate expression');
|
||||
// Ignore error since most likely it’s because of non-math expression
|
||||
@ -31,5 +49,4 @@ export function evaluateMathExpression() {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'mocha';
|
||||
import * as assert from 'assert';
|
||||
import { Position, Selection } from 'vscode';
|
||||
import { withRandomFileEditor, closeAllEditors } from './testUtils';
|
||||
import { evaluateMathExpression } from '../evaluateMathExpression';
|
||||
|
||||
suite('Tests for Evaluate Math Expression', () => {
|
||||
teardown(closeAllEditors);
|
||||
|
||||
function testEvaluateMathExpression(fileContents: string, selection: [number, number] | number, expectedFileContents: string): Thenable<boolean> {
|
||||
return withRandomFileEditor(fileContents, 'html', async (editor, _doc) => {
|
||||
const selectionToUse = typeof selection === 'number' ?
|
||||
new Selection(new Position(0, selection), new Position(0, selection)) :
|
||||
new Selection(new Position(0, selection[0]), new Position(0, selection[1]));
|
||||
editor.selection = selectionToUse;
|
||||
|
||||
await evaluateMathExpression();
|
||||
|
||||
assert.strictEqual(editor.document.getText(), expectedFileContents);
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
test('Selected sanity check', () => {
|
||||
return testEvaluateMathExpression('1 + 2', [0, 5], '3');
|
||||
});
|
||||
|
||||
test('Selected with surrounding text', () => {
|
||||
return testEvaluateMathExpression('test1 + 2test', [4, 9], 'test3test');
|
||||
});
|
||||
|
||||
test('Selected with number not part of selection', () => {
|
||||
return testEvaluateMathExpression('test3 1+2', [6, 9], 'test3 3');
|
||||
});
|
||||
|
||||
test('Non-selected sanity check', () => {
|
||||
return testEvaluateMathExpression('1 + 2', 5, '3');
|
||||
});
|
||||
|
||||
test('Non-selected midway', () => {
|
||||
return testEvaluateMathExpression('1 + 2', 1, '1 + 2');
|
||||
});
|
||||
|
||||
test('Non-selected with surrounding text', () => {
|
||||
return testEvaluateMathExpression('test1 + 3test', 9, 'test4test');
|
||||
});
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module '@emmetio/math-expression' {
|
||||
import { BufferStream } from 'EmmetNode';
|
||||
|
||||
function index(stream: BufferStream, backward: boolean): number;
|
||||
|
||||
export default index;
|
||||
}
|
||||
|
@ -31,13 +31,12 @@
|
||||
"@emmetio/stream-reader" "^2.0.0"
|
||||
"@emmetio/stream-reader-utils" "^0.1.0"
|
||||
|
||||
"@emmetio/math-expression@^0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@emmetio/math-expression/-/math-expression-0.1.1.tgz#1ff2c7f05800f64c57ca89038ee18bce9f5776dc"
|
||||
integrity sha1-H/LH8FgA9kxXyokDjuGLzp9Xdtw=
|
||||
"@emmetio/math-expression@^1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@emmetio/math-expression/-/math-expression-1.0.4.tgz#cb657ed944f82b3728f863bf5ece1b1ff3ae7497"
|
||||
integrity sha512-1m7y8/VeXCAfgFoPGTerbqCIadApcIINujd3TaM/LRLPPKiod8aT1PPmh542spnsUSsSnZJjbuF7xiO4WFA42g==
|
||||
dependencies:
|
||||
"@emmetio/stream-reader" "^2.0.1"
|
||||
"@emmetio/stream-reader-utils" "^0.1.0"
|
||||
"@emmetio/scanner" "^1.0.0"
|
||||
|
||||
"@emmetio/scanner@^1.0.0":
|
||||
version "1.0.0"
|
||||
@ -49,15 +48,15 @@
|
||||
resolved "https://registry.yarnpkg.com/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz#244cb02c77ec2e74f78a9bd318218abc9c500a61"
|
||||
integrity sha1-JEywLHfsLnT3ipvTGCGKvJxQCmE=
|
||||
|
||||
"@emmetio/stream-reader@^2.0.0", "@emmetio/stream-reader@^2.0.1", "@emmetio/stream-reader@^2.2.0":
|
||||
"@emmetio/stream-reader@^2.0.0", "@emmetio/stream-reader@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz#46cffea119a0a003312a21c2d9b5628cb5fcd442"
|
||||
integrity sha1-Rs/+oRmgoAMxKiHC2bVijLX81EI=
|
||||
|
||||
"@types/node@^12.11.7":
|
||||
version "12.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.2.tgz#9565ed5c72ba96038fc3add643edd5e7820598e7"
|
||||
integrity sha512-SRH6QM0IMOBBFmDiJ75vlhcbUEYEquvSuhsVW9ijG20JvdFTfOrB1p6ddZxz5y/JNnbf+9HoHhjhOVSX2hsJyA==
|
||||
version "12.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.4.tgz#cdfbb62e26c7435ed9aab9c941393cc3598e9b46"
|
||||
integrity sha512-o3oj1bETk8kBwzz1WlO6JWL/AfAA3Vm6J1B3C9CsdxHYp7XgPiH7OEXPUbZTndHlRaIElrANkQfe6ZmfJb3H2w==
|
||||
|
||||
ajv@^6.12.3:
|
||||
version "6.12.6"
|
||||
@ -178,9 +177,9 @@ aws-sign2@~0.7.0:
|
||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.10.1"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
|
||||
integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
@ -392,12 +391,12 @@ debug@^2.2.0:
|
||||
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==
|
||||
debug@^4.1.1:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
|
||||
integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
ms "2.1.2"
|
||||
|
||||
decamelize@^1.1.2:
|
||||
version "1.2.0"
|
||||
@ -994,9 +993,9 @@ is-buffer@^1.1.5, is-buffer@~1.1.6:
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
|
||||
is-core-module@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.0.0.tgz#58531b70aed1db7c0e8d4eb1a0a2d1ddd64bd12d"
|
||||
integrity sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946"
|
||||
integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==
|
||||
dependencies:
|
||||
has "^1.0.3"
|
||||
|
||||
@ -1410,7 +1409,7 @@ lodash.values@~2.4.1:
|
||||
dependencies:
|
||||
lodash.keys "~2.4.1"
|
||||
|
||||
lodash@^4.16.4:
|
||||
lodash@^4.17.15:
|
||||
version "4.17.20"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
|
||||
@ -1572,12 +1571,12 @@ mocha-junit-reporter@^1.17.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=
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz#c73486bed5519e1d59c9ce39ac7a9792600e5676"
|
||||
integrity sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg==
|
||||
dependencies:
|
||||
debug "^3.1.0"
|
||||
lodash "^4.16.4"
|
||||
debug "^4.1.1"
|
||||
lodash "^4.17.15"
|
||||
|
||||
mocha@^2.3.3:
|
||||
version "2.5.3"
|
||||
@ -1605,7 +1604,7 @@ ms@2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
ms@^2.1.1:
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
@ -2413,14 +2412,15 @@ vinyl@~2.0.1:
|
||||
replace-ext "^1.0.0"
|
||||
|
||||
vscode-emmet-helper@~2.0.0:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.0.8.tgz#7c3cf8027d1a75d29625e029d516da7bc56c1fdb"
|
||||
integrity sha512-Wyf+b5pua+13eZSHCpmob1x915x/od4z6lIia9T2N4v7+CUYNxDisBu3/ShIM3qg3YiYvTCOm+Yx/CLd2khcVw==
|
||||
version "2.0.9"
|
||||
resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.0.9.tgz#16244c087cba4e379116f268384bb644649db6ad"
|
||||
integrity sha512-S6RjnR9gUicl8LsYnQAMNqqOxolud9gcj+NpPyEnxfxp1YIBuC9oetj6l6N9VMZBWu6tL77wmf+/EJsRx1PDPA==
|
||||
dependencies:
|
||||
emmet "^2.1.5"
|
||||
jsonc-parser "^2.3.0"
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "^3.15.1"
|
||||
vscode-nls "^5.0.0"
|
||||
vscode-uri "^2.1.2"
|
||||
|
||||
vscode-html-languageservice@^3.0.3:
|
||||
|
@ -181,6 +181,12 @@
|
||||
"category": "Git",
|
||||
"icon": "$(discard)"
|
||||
},
|
||||
{
|
||||
"command": "git.rename",
|
||||
"title": "%command.rename%",
|
||||
"category": "Git",
|
||||
"icon": "$(discard)"
|
||||
},
|
||||
{
|
||||
"command": "git.commit",
|
||||
"title": "%command.commit%",
|
||||
@ -278,6 +284,11 @@
|
||||
"title": "%command.checkout%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.checkoutDetached",
|
||||
"title": "%command.checkoutDetached%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.branch",
|
||||
"title": "%command.branch%",
|
||||
@ -368,6 +379,11 @@
|
||||
"title": "%command.pushToForce%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.pushTags",
|
||||
"title": "%command.pushTags%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.pushWithTags",
|
||||
"title": "%command.pushFollowTags%",
|
||||
@ -378,6 +394,11 @@
|
||||
"title": "%command.pushFollowTagsForce%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.cherryPick",
|
||||
"title": "%command.cherryPick%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.addRemote",
|
||||
"title": "%command.addRemote%",
|
||||
@ -605,6 +626,10 @@
|
||||
"command": "git.cleanAllUntracked",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.rename",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && resourceScheme == file"
|
||||
},
|
||||
{
|
||||
"command": "git.commit",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
@ -705,6 +730,10 @@
|
||||
"command": "git.renameBranch",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.cherryPick",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.pull",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
@ -769,6 +798,10 @@
|
||||
"command": "git.pushWithTagsForce",
|
||||
"when": "config.git.enabled && !git.missing && config.git.allowForcePush && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.pushTags",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.addRemote",
|
||||
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||
@ -1279,17 +1312,17 @@
|
||||
{
|
||||
"command": "git.stageSelectedRanges",
|
||||
"group": "2_git@1",
|
||||
"when": "isInDiffRightEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
"when": "isInDiffRightEditor && !isInEmbeddedDiffEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageSelectedRanges",
|
||||
"group": "2_git@2",
|
||||
"when": "isInDiffRightEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
"when": "isInDiffRightEditor && !isInEmbeddedDiffEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
},
|
||||
{
|
||||
"command": "git.revertSelectedRanges",
|
||||
"group": "2_git@3",
|
||||
"when": "isInDiffRightEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
"when": "isInDiffRightEditor && !isInEmbeddedDiffEditor && config.git.enabled && !git.missing && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
}
|
||||
],
|
||||
"scm/change/title": [
|
||||
@ -1657,21 +1690,27 @@
|
||||
"scope": "resource"
|
||||
},
|
||||
"git.checkoutType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"all",
|
||||
"local",
|
||||
"tags",
|
||||
"remote"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%config.checkoutType.all%",
|
||||
"%config.checkoutType.local%",
|
||||
"%config.checkoutType.tags%",
|
||||
"%config.checkoutType.remote%"
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"local",
|
||||
"tags",
|
||||
"remote"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%config.checkoutType.local%",
|
||||
"%config.checkoutType.tags%",
|
||||
"%config.checkoutType.remote%"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true,
|
||||
"markdownDescription": "%config.checkoutType%",
|
||||
"default": "all"
|
||||
"default": [
|
||||
"local",
|
||||
"remote",
|
||||
"tags"
|
||||
]
|
||||
},
|
||||
"git.ignoreLegacyWarning": {
|
||||
"type": "boolean",
|
||||
@ -1751,6 +1790,28 @@
|
||||
"description": "%config.enableStatusBarSync%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"git.followTagsWhenSync": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": false,
|
||||
"description": "%config.followTagsWhenSync%"
|
||||
},
|
||||
"git.promptToSaveFilesBeforeStash": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"always",
|
||||
"staged",
|
||||
"never"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%config.promptToSaveFilesBeforeStash.always%",
|
||||
"%config.promptToSaveFilesBeforeStash.staged%",
|
||||
"%config.promptToSaveFilesBeforeStash.never%"
|
||||
],
|
||||
"scope": "resource",
|
||||
"default": "always",
|
||||
"description": "%config.promptToSaveFilesBeforeStash%"
|
||||
},
|
||||
"git.promptToSaveFilesBeforeCommit": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@ -1783,6 +1844,23 @@
|
||||
"scope": "resource",
|
||||
"default": "none"
|
||||
},
|
||||
"git.openAfterClone": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"always",
|
||||
"alwaysNewWindow",
|
||||
"whenNoFolderOpen",
|
||||
"prompt"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%config.openAfterClone.always%",
|
||||
"%config.openAfterClone.alwaysNewWindow%",
|
||||
"%config.openAfterClone.whenNoFolderOpen%",
|
||||
"%config.openAfterClone.prompt%"
|
||||
],
|
||||
"default": "prompt",
|
||||
"description": "%config.openAfterClone%"
|
||||
},
|
||||
"git.showInlineOpenFileAction": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
@ -1840,6 +1918,12 @@
|
||||
"default": false,
|
||||
"description": "%config.alwaysSignOff%"
|
||||
},
|
||||
"git.ignoreSubmodules": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": false,
|
||||
"description": "%config.ignoreSubmodules%"
|
||||
},
|
||||
"git.ignoredRepositories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@ -1876,6 +1960,12 @@
|
||||
"default": false,
|
||||
"description": "%config.fetchOnPull%"
|
||||
},
|
||||
"git.pruneOnFetch": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": false,
|
||||
"description": "%config.pruneOnFetch%"
|
||||
},
|
||||
"git.pullTags": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
@ -1962,6 +2052,12 @@
|
||||
"default": true,
|
||||
"description": "%config.terminalAuthentication%"
|
||||
},
|
||||
"git.useCommitInputAsStashMessage": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": false,
|
||||
"description": "%config.useCommitInputAsStashMessage%"
|
||||
},
|
||||
"git.githubAuthentication": {
|
||||
"deprecationMessage": "This setting is now deprecated, please use `github.gitAuthentication` instead."
|
||||
},
|
||||
@ -2166,31 +2262,36 @@
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.empty%",
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == empty",
|
||||
"when": "config.git.enabled && workbenchState == empty",
|
||||
"enablement": "git.state == initialized",
|
||||
"group": "2_open@1"
|
||||
},
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.folder%",
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == folder",
|
||||
"when": "config.git.enabled && workbenchState == folder",
|
||||
"enablement": "git.state == initialized",
|
||||
"group": "5_scm@1"
|
||||
},
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.workspace%",
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0",
|
||||
"when": "config.git.enabled && workbenchState == workspace && workspaceFolderCount != 0",
|
||||
"enablement": "git.state == initialized",
|
||||
"group": "5_scm@1"
|
||||
},
|
||||
{
|
||||
"view": "scm",
|
||||
"contents": "%view.workbench.scm.emptyWorkspace%",
|
||||
"when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount == 0",
|
||||
"when": "config.git.enabled && workbenchState == workspace && workspaceFolderCount == 0",
|
||||
"enablement": "git.state == initialized",
|
||||
"group": "2_open@1"
|
||||
},
|
||||
{
|
||||
"view": "explorer",
|
||||
"contents": "%view.workbench.cloneRepository%",
|
||||
"when": "config.git.enabled && git.state == initialized",
|
||||
"when": "config.git.enabled",
|
||||
"enablement": "git.state == initialized",
|
||||
"group": "5_scm@1"
|
||||
}
|
||||
]
|
||||
|
@ -23,6 +23,7 @@
|
||||
"command.unstage": "Unstage Changes",
|
||||
"command.unstageAll": "Unstage All Changes",
|
||||
"command.unstageSelectedRanges": "Unstage Selected Ranges",
|
||||
"command.rename": "Rename",
|
||||
"command.clean": "Discard Changes",
|
||||
"command.cleanAll": "Discard All Changes",
|
||||
"command.cleanAllTracked": "Discard All Tracked Changes",
|
||||
@ -46,10 +47,12 @@
|
||||
"command.restoreCommitTemplate": "Restore Commit Template",
|
||||
"command.undoCommit": "Undo Last Commit",
|
||||
"command.checkout": "Checkout to...",
|
||||
"command.checkoutDetached": "Checkout to (Detached)...",
|
||||
"command.branch": "Create Branch...",
|
||||
"command.branchFrom": "Create Branch From...",
|
||||
"command.deleteBranch": "Delete Branch...",
|
||||
"command.renameBranch": "Rename Branch...",
|
||||
"command.cherryPick": "Cherry Pick...",
|
||||
"command.merge": "Merge Branch...",
|
||||
"command.rebase": "Rebase Branch...",
|
||||
"command.createTag": "Create Tag",
|
||||
@ -66,6 +69,7 @@
|
||||
"command.pushToForce": "Push to... (Force)",
|
||||
"command.pushFollowTags": "Push (Follow Tags)",
|
||||
"command.pushFollowTagsForce": "Push (Follow Tags, Force)",
|
||||
"command.pushTags": "Push Tags",
|
||||
"command.addRemote": "Add Remote...",
|
||||
"command.removeRemote": "Remove Remote",
|
||||
"command.sync": "Sync",
|
||||
@ -100,11 +104,10 @@
|
||||
"config.countBadge.all": "Count all changes.",
|
||||
"config.countBadge.tracked": "Count only tracked changes.",
|
||||
"config.countBadge.off": "Turn off counter.",
|
||||
"config.checkoutType": "Controls what type of branches are listed when running `Checkout to...`.",
|
||||
"config.checkoutType.all": "Show all references.",
|
||||
"config.checkoutType.local": "Show only local branches.",
|
||||
"config.checkoutType.tags": "Show only tags.",
|
||||
"config.checkoutType.remote": "Show only remote branches.",
|
||||
"config.checkoutType": "Controls what type of git refs are listed when running `Checkout to...`.",
|
||||
"config.checkoutType.local": "Local branches",
|
||||
"config.checkoutType.tags": "Tags",
|
||||
"config.checkoutType.remote": "Remote branches",
|
||||
"config.branchValidationRegex": "A regular expression to validate new branch names.",
|
||||
"config.branchWhitespaceChar": "The character to replace whitespace in new branch names.",
|
||||
"config.ignoreLegacyWarning": "Ignores the legacy Git warning.",
|
||||
@ -121,6 +124,11 @@
|
||||
"config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run.",
|
||||
"config.decorations.enabled": "Controls whether Git contributes colors and badges to the explorer and the open editors view.",
|
||||
"config.enableStatusBarSync": "Controls whether the Git Sync command appears in the status bar.",
|
||||
"config.followTagsWhenSync": "Follow push all tags when running the sync command.",
|
||||
"config.promptToSaveFilesBeforeStash": "Controls whether Git should check for unsaved files before stashing changes.",
|
||||
"config.promptToSaveFilesBeforeStash.always": "Check for any unsaved files.",
|
||||
"config.promptToSaveFilesBeforeStash.staged": "Check only for unsaved staged files.",
|
||||
"config.promptToSaveFilesBeforeStash.never": "Disable this check.",
|
||||
"config.promptToSaveFilesBeforeCommit": "Controls whether Git should check for unsaved files before committing.",
|
||||
"config.promptToSaveFilesBeforeCommit.always": "Check for any unsaved files.",
|
||||
"config.promptToSaveFilesBeforeCommit.staged": "Check only for unsaved staged files.",
|
||||
@ -129,6 +137,11 @@
|
||||
"config.postCommitCommand.none": "Don't run any command after a commit.",
|
||||
"config.postCommitCommand.push": "Run 'Git Push' after a successful commit.",
|
||||
"config.postCommitCommand.sync": "Run 'Git Sync' after a successful commit.",
|
||||
"config.openAfterClone": "Controls whether to open a repository automatically after cloning.",
|
||||
"config.openAfterClone.always": "Always open in current window.",
|
||||
"config.openAfterClone.alwaysNewWindow": "Always open in a new window.",
|
||||
"config.openAfterClone.whenNoFolderOpen": "Only open in current window when no folder is opened.",
|
||||
"config.openAfterClone.prompt": "Always prompt for action.",
|
||||
"config.showInlineOpenFileAction": "Controls whether to show an inline Open File action in the Git changes view.",
|
||||
"config.showPushSuccessNotification": "Controls whether to show a notification when a push is successful.",
|
||||
"config.inputValidation": "Controls when to show commit message input validation.",
|
||||
@ -138,6 +151,7 @@
|
||||
"config.detectSubmodulesLimit": "Controls the limit of git submodules detected.",
|
||||
"config.alwaysShowStagedChangesResourceGroup": "Always show the Staged Changes resource group.",
|
||||
"config.alwaysSignOff": "Controls the signoff flag for all commits.",
|
||||
"config.ignoreSubmodules": "Ignore modifications to submodules in the file tree.",
|
||||
"config.ignoredRepositories": "List of git repositories to ignore.",
|
||||
"config.scanRepositories": "List of paths to search for git repositories in.",
|
||||
"config.showProgress": "Controls whether git actions should show progress.",
|
||||
@ -145,6 +159,7 @@
|
||||
"config.confirmEmptyCommits": "Always confirm the creation of empty commits for the 'Git: Commit Empty' command.",
|
||||
"config.fetchOnPull": "When enabled, fetch all branches when pulling. Otherwise, fetch just the current one.",
|
||||
"config.pullTags": "Fetch all tags when pulling.",
|
||||
"config.pruneOnFetch": "Prune when fetching.",
|
||||
"config.autoStash": "Stash any changes before pulling and restore them after successful pull.",
|
||||
"config.allowForcePush": "Controls whether force push (with or without lease) is enabled.",
|
||||
"config.useForcePushWithLease": "Controls whether force pushing uses the safer force-with-lease variant.",
|
||||
@ -164,6 +179,8 @@
|
||||
"config.timeline.date": "Controls which date to use for items in the Timeline view",
|
||||
"config.timeline.date.committed": "Use the committed date",
|
||||
"config.timeline.date.authored": "Use the authored date",
|
||||
"config.useCommitInputAsStashMessage": "Controls whether to use the message from the commit input box as the default stash message.",
|
||||
"submenu.explorer": "Git",
|
||||
"submenu.commit": "Commit",
|
||||
"submenu.commit.amend": "Amend",
|
||||
"submenu.commit.signoff": "Sign Off",
|
||||
@ -188,5 +205,5 @@
|
||||
"view.workbench.scm.folder": "The folder currently open doesn't have a git repository. You can initialize a repository which will enable source control features powered by git.\n[Initialize Repository](command:git.init?%5Btrue%5D)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).",
|
||||
"view.workbench.scm.workspace": "The workspace currently open doesn't have any folders containing git repositories. You can initialize a repository on a folder which will enable source control features powered by git.\n[Initialize Repository](command:git.init)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).",
|
||||
"view.workbench.scm.emptyWorkspace": "The workspace currently open doesn't have any folders containing git repositories.\n[Add Folder to Workspace](command:workbench.action.addRootFolder)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).",
|
||||
"view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).\n[Clone Repository](command:git.clone)"
|
||||
"view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).\n[Clone Repository](command:git.clone 'Clone a repository once the git extension has activated')"
|
||||
}
|
||||
|
@ -357,7 +357,7 @@ export function registerAPICommands(extension: GitExtensionImpl): Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
return pickRemoteSource(extension.model, opts);
|
||||
return pickRemoteSource(extension.model, opts as any);
|
||||
}));
|
||||
|
||||
return Disposable.from(...disposables);
|
||||
|
1
lib/vscode/extensions/git/src/api/git.d.ts
vendored
1
lib/vscode/extensions/git/src/api/git.d.ts
vendored
@ -212,6 +212,7 @@ export interface RemoteSourceProvider {
|
||||
readonly icon?: string; // codicon name
|
||||
readonly supportsQuery?: boolean;
|
||||
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
|
||||
getBranches?(url: string): ProviderResult<string[]>;
|
||||
publishRepository?(repository: Repository): Promise<void>;
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,9 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { lstat, Stats } from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection } from 'vscode';
|
||||
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider } from 'vscode';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch, GitErrorCodes, Ref, RefType, Status, CommitOptions, RemoteSourceProvider } from './api/git';
|
||||
@ -31,14 +30,14 @@ class CheckoutItem implements QuickPickItem {
|
||||
|
||||
constructor(protected ref: Ref) { }
|
||||
|
||||
async run(repository: Repository): Promise<void> {
|
||||
async run(repository: Repository, opts?: { detached?: boolean }): Promise<void> {
|
||||
const ref = this.ref.name;
|
||||
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.checkout(ref);
|
||||
await repository.checkout(ref, opts);
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +54,7 @@ class CheckoutRemoteHeadItem extends CheckoutItem {
|
||||
return localize('remote branch at', "Remote branch at {0}", this.shortCommit);
|
||||
}
|
||||
|
||||
async run(repository: Repository): Promise<void> {
|
||||
async run(repository: Repository, opts?: { detached?: boolean }): Promise<void> {
|
||||
if (!this.ref.name) {
|
||||
return;
|
||||
}
|
||||
@ -63,9 +62,9 @@ class CheckoutRemoteHeadItem extends CheckoutItem {
|
||||
const branches = await repository.findTrackingBranches(this.ref.name);
|
||||
|
||||
if (branches.length > 0) {
|
||||
await repository.checkout(branches[0].name!);
|
||||
await repository.checkout(branches[0].name!, opts);
|
||||
} else {
|
||||
await repository.checkoutTracking(this.ref.name);
|
||||
await repository.checkoutTracking(this.ref.name, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,31 +113,21 @@ class RebaseItem implements QuickPickItem {
|
||||
}
|
||||
|
||||
class CreateBranchItem implements QuickPickItem {
|
||||
|
||||
constructor(private cc: CommandCenter) { }
|
||||
|
||||
get label(): string { return '$(plus) ' + localize('create branch', 'Create new branch...'); }
|
||||
get description(): string { return ''; }
|
||||
|
||||
get alwaysShow(): boolean { return true; }
|
||||
|
||||
async run(repository: Repository): Promise<void> {
|
||||
await this.cc.branch(repository);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateBranchFromItem implements QuickPickItem {
|
||||
|
||||
constructor(private cc: CommandCenter) { }
|
||||
|
||||
get label(): string { return '$(plus) ' + localize('create branch from', 'Create new branch from...'); }
|
||||
get description(): string { return ''; }
|
||||
|
||||
get alwaysShow(): boolean { return true; }
|
||||
}
|
||||
|
||||
async run(repository: Repository): Promise<void> {
|
||||
await this.cc.branch(repository);
|
||||
}
|
||||
class CheckoutDetachedItem implements QuickPickItem {
|
||||
get label(): string { return '$(debug-disconnect) ' + localize('checkout detached', 'Checkout detached...'); }
|
||||
get description(): string { return ''; }
|
||||
get alwaysShow(): boolean { return true; }
|
||||
}
|
||||
|
||||
class HEADItem implements QuickPickItem {
|
||||
@ -217,18 +206,53 @@ async function categorizeResourceByResolution(resources: Resource[]): Promise<{
|
||||
|
||||
function createCheckoutItems(repository: Repository): CheckoutItem[] {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const checkoutType = config.get<string>('checkoutType') || 'all';
|
||||
const includeTags = checkoutType === 'all' || checkoutType === 'tags';
|
||||
const includeRemotes = checkoutType === 'all' || checkoutType === 'remote';
|
||||
const checkoutTypeConfig = config.get<string | string[]>('checkoutType');
|
||||
let checkoutTypes: string[];
|
||||
|
||||
const heads = repository.refs.filter(ref => ref.type === RefType.Head)
|
||||
.map(ref => new CheckoutItem(ref));
|
||||
const tags = (includeTags ? repository.refs.filter(ref => ref.type === RefType.Tag) : [])
|
||||
.map(ref => new CheckoutTagItem(ref));
|
||||
const remoteHeads = (includeRemotes ? repository.refs.filter(ref => ref.type === RefType.RemoteHead) : [])
|
||||
.map(ref => new CheckoutRemoteHeadItem(ref));
|
||||
if (checkoutTypeConfig === 'all' || !checkoutTypeConfig || checkoutTypeConfig.length === 0) {
|
||||
checkoutTypes = ['local', 'remote', 'tags'];
|
||||
} else if (typeof checkoutTypeConfig === 'string') {
|
||||
checkoutTypes = [checkoutTypeConfig];
|
||||
} else {
|
||||
checkoutTypes = checkoutTypeConfig;
|
||||
}
|
||||
|
||||
return [...heads, ...tags, ...remoteHeads];
|
||||
const processors = checkoutTypes.map(getCheckoutProcessor)
|
||||
.filter(p => !!p) as CheckoutProcessor[];
|
||||
|
||||
for (const ref of repository.refs) {
|
||||
for (const processor of processors) {
|
||||
processor.onRef(ref);
|
||||
}
|
||||
}
|
||||
|
||||
return processors.reduce<CheckoutItem[]>((r, p) => r.concat(...p.items), []);
|
||||
}
|
||||
|
||||
class CheckoutProcessor {
|
||||
|
||||
private refs: Ref[] = [];
|
||||
get items(): CheckoutItem[] { return this.refs.map(r => new this.ctor(r)); }
|
||||
constructor(private type: RefType, private ctor: { new(ref: Ref): CheckoutItem }) { }
|
||||
|
||||
onRef(ref: Ref): void {
|
||||
if (ref.type === this.type) {
|
||||
this.refs.push(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCheckoutProcessor(type: string): CheckoutProcessor | undefined {
|
||||
switch (type) {
|
||||
case 'local':
|
||||
return new CheckoutProcessor(RefType.Head, CheckoutItem);
|
||||
case 'remote':
|
||||
return new CheckoutProcessor(RefType.RemoteHead, CheckoutRemoteHeadItem);
|
||||
case 'tags':
|
||||
return new CheckoutProcessor(RefType.Tag, CheckoutTagItem);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function sanitizeRemoteName(name: string) {
|
||||
@ -246,6 +270,7 @@ enum PushType {
|
||||
Push,
|
||||
PushTo,
|
||||
PushFollowTags,
|
||||
PushTags
|
||||
}
|
||||
|
||||
interface PushOptions {
|
||||
@ -254,9 +279,27 @@ interface PushOptions {
|
||||
silent?: boolean;
|
||||
}
|
||||
|
||||
class CommandErrorOutputTextDocumentContentProvider implements TextDocumentContentProvider {
|
||||
|
||||
private items = new Map<string, string>();
|
||||
|
||||
set(uri: Uri, contents: string): void {
|
||||
this.items.set(uri.path, contents);
|
||||
}
|
||||
|
||||
delete(uri: Uri): void {
|
||||
this.items.delete(uri.path);
|
||||
}
|
||||
|
||||
provideTextDocumentContent(uri: Uri): string | undefined {
|
||||
return this.items.get(uri.path);
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandCenter {
|
||||
|
||||
private disposables: Disposable[];
|
||||
private commandErrors = new CommandErrorOutputTextDocumentContentProvider();
|
||||
|
||||
constructor(
|
||||
private git: Git,
|
||||
@ -273,6 +316,8 @@ export class CommandCenter {
|
||||
return commands.registerCommand(commandId, command);
|
||||
}
|
||||
});
|
||||
|
||||
this.disposables.push(workspace.registerTextDocumentContentProvider('git-output', this.commandErrors));
|
||||
}
|
||||
|
||||
@command('git.setLogLevel')
|
||||
@ -311,165 +356,14 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
@command('git.openResource')
|
||||
async openResource(resource: Resource, preserveFocus: boolean): Promise<void> {
|
||||
async openResource(resource: Resource): Promise<void> {
|
||||
const repository = this.model.getRepository(resource.resourceUri);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = workspace.getConfiguration('git', Uri.file(repository.root));
|
||||
const openDiffOnClick = config.get<boolean>('openDiffOnClick');
|
||||
|
||||
if (openDiffOnClick) {
|
||||
await this._openResource(resource, undefined, preserveFocus, false);
|
||||
} else {
|
||||
await this.openFile(resource);
|
||||
}
|
||||
}
|
||||
|
||||
private async _openResource(resource: Resource, preview?: boolean, preserveFocus?: boolean, preserveSelection?: boolean): Promise<void> {
|
||||
let stat: Stats | undefined;
|
||||
|
||||
try {
|
||||
stat = await new Promise<Stats>((c, e) => lstat(resource.resourceUri.fsPath, (err, stat) => err ? e(err) : c(stat)));
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
|
||||
let left: Uri | undefined;
|
||||
let right: Uri | undefined;
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
const repository = this.model.getRepositoryForSubmodule(resource.resourceUri);
|
||||
|
||||
if (repository) {
|
||||
right = toGitUri(resource.resourceUri, resource.resourceGroupType === ResourceGroupType.Index ? 'index' : 'wt', { submoduleOf: repository.root });
|
||||
}
|
||||
} else {
|
||||
if (resource.type !== Status.DELETED_BY_THEM) {
|
||||
left = this.getLeftResource(resource);
|
||||
}
|
||||
|
||||
right = this.getRightResource(resource);
|
||||
}
|
||||
|
||||
const title = this.getTitle(resource);
|
||||
|
||||
if (!right) {
|
||||
// TODO
|
||||
console.error('oh no');
|
||||
return;
|
||||
}
|
||||
|
||||
const opts: TextDocumentShowOptions = {
|
||||
preserveFocus,
|
||||
preview,
|
||||
viewColumn: ViewColumn.Active
|
||||
};
|
||||
|
||||
const activeTextEditor = window.activeTextEditor;
|
||||
|
||||
// Check if active text editor has same path as other editor. we cannot compare via
|
||||
// URI.toString() here because the schemas can be different. Instead we just go by path.
|
||||
if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.path === right.path) {
|
||||
opts.selection = activeTextEditor.selection;
|
||||
}
|
||||
|
||||
if (!left) {
|
||||
await commands.executeCommand<void>('vscode.open', right, opts, title);
|
||||
} else {
|
||||
await commands.executeCommand<void>('vscode.diff', left, right, title, opts);
|
||||
}
|
||||
}
|
||||
|
||||
private getLeftResource(resource: Resource): Uri | undefined {
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
case Status.INDEX_ADDED:
|
||||
return toGitUri(resource.original, 'HEAD');
|
||||
|
||||
case Status.MODIFIED:
|
||||
case Status.UNTRACKED:
|
||||
return toGitUri(resource.resourceUri, '~');
|
||||
|
||||
case Status.DELETED_BY_THEM:
|
||||
return toGitUri(resource.resourceUri, '');
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getRightResource(resource: Resource): Uri | undefined {
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_ADDED:
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
return toGitUri(resource.resourceUri, '');
|
||||
|
||||
case Status.INDEX_DELETED:
|
||||
case Status.DELETED:
|
||||
return toGitUri(resource.resourceUri, 'HEAD');
|
||||
|
||||
case Status.DELETED_BY_US:
|
||||
return toGitUri(resource.resourceUri, '~3');
|
||||
|
||||
case Status.DELETED_BY_THEM:
|
||||
return toGitUri(resource.resourceUri, '~2');
|
||||
|
||||
case Status.MODIFIED:
|
||||
case Status.UNTRACKED:
|
||||
case Status.IGNORED:
|
||||
case Status.INTENT_TO_ADD:
|
||||
const repository = this.model.getRepository(resource.resourceUri);
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uriString = resource.resourceUri.toString();
|
||||
const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
|
||||
|
||||
if (indexStatus && indexStatus.renameResourceUri) {
|
||||
return indexStatus.renameResourceUri;
|
||||
}
|
||||
|
||||
return resource.resourceUri;
|
||||
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return resource.resourceUri;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getTitle(resource: Resource): string {
|
||||
const basename = path.basename(resource.resourceUri.fsPath);
|
||||
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
case Status.INDEX_ADDED:
|
||||
return localize('git.title.index', '{0} (Index)', basename);
|
||||
|
||||
case Status.MODIFIED:
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return localize('git.title.workingTree', '{0} (Working Tree)', basename);
|
||||
|
||||
case Status.DELETED_BY_US:
|
||||
return localize('git.title.theirs', '{0} (Theirs)', basename);
|
||||
|
||||
case Status.DELETED_BY_THEM:
|
||||
return localize('git.title.ours', '{0} (Ours)', basename);
|
||||
|
||||
case Status.UNTRACKED:
|
||||
return localize('git.title.untracked', '{0} (Untracked)', basename);
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
await resource.open();
|
||||
}
|
||||
|
||||
async cloneRepository(url?: string, parentPath?: string, options: { recursive?: boolean } = {}): Promise<void> {
|
||||
@ -531,35 +425,54 @@ export class CommandCenter {
|
||||
(progress, token) => this.git.clone(url!, { parentPath: parentPath!, progress, recursive: options.recursive }, token)
|
||||
);
|
||||
|
||||
let message = localize('proposeopen', "Would you like to open the cloned repository?");
|
||||
const open = localize('openrepo', "Open");
|
||||
const openNewWindow = localize('openreponew', "Open in New Window");
|
||||
const choices = [open, openNewWindow];
|
||||
const config = workspace.getConfiguration('git');
|
||||
const openAfterClone = config.get<'always' | 'alwaysNewWindow' | 'whenNoFolderOpen' | 'prompt'>('openAfterClone');
|
||||
|
||||
const addToWorkspace = localize('add', "Add to Workspace");
|
||||
if (workspace.workspaceFolders) {
|
||||
message = localize('proposeopen2', "Would you like to open the cloned repository, or add it to the current workspace?");
|
||||
choices.push(addToWorkspace);
|
||||
enum PostCloneAction { Open, OpenNewWindow, AddToWorkspace }
|
||||
let action: PostCloneAction | undefined = undefined;
|
||||
|
||||
if (openAfterClone === 'always') {
|
||||
action = PostCloneAction.Open;
|
||||
} else if (openAfterClone === 'alwaysNewWindow') {
|
||||
action = PostCloneAction.OpenNewWindow;
|
||||
} else if (openAfterClone === 'whenNoFolderOpen' && !workspace.workspaceFolders) {
|
||||
action = PostCloneAction.Open;
|
||||
}
|
||||
|
||||
const result = await window.showInformationMessage(message, ...choices);
|
||||
if (action === undefined) {
|
||||
let message = localize('proposeopen', "Would you like to open the cloned repository?");
|
||||
const open = localize('openrepo', "Open");
|
||||
const openNewWindow = localize('openreponew', "Open in New Window");
|
||||
const choices = [open, openNewWindow];
|
||||
|
||||
const addToWorkspace = localize('add', "Add to Workspace");
|
||||
if (workspace.workspaceFolders) {
|
||||
message = localize('proposeopen2', "Would you like to open the cloned repository, or add it to the current workspace?");
|
||||
choices.push(addToWorkspace);
|
||||
}
|
||||
|
||||
const result = await window.showInformationMessage(message, ...choices);
|
||||
|
||||
action = result === open ? PostCloneAction.Open
|
||||
: result === openNewWindow ? PostCloneAction.OpenNewWindow
|
||||
: result === addToWorkspace ? PostCloneAction.AddToWorkspace : undefined;
|
||||
}
|
||||
|
||||
const openFolder = result === open;
|
||||
/* __GDPR__
|
||||
"clone" : {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"openFolder": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'success' }, { openFolder: openFolder ? 1 : 0 });
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'success' }, { openFolder: action === PostCloneAction.Open || action === PostCloneAction.OpenNewWindow ? 1 : 0 });
|
||||
|
||||
const uri = Uri.file(repositoryPath);
|
||||
|
||||
if (openFolder) {
|
||||
if (action === PostCloneAction.Open) {
|
||||
commands.executeCommand('vscode.openFolder', uri, { forceReuseWindow: true });
|
||||
} else if (result === addToWorkspace) {
|
||||
} else if (action === PostCloneAction.AddToWorkspace) {
|
||||
workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri });
|
||||
} else if (result === openNewWindow) {
|
||||
} else if (action === PostCloneAction.OpenNewWindow) {
|
||||
commands.executeCommand('vscode.openFolder', uri, { forceNewWindow: true });
|
||||
}
|
||||
} catch (err) {
|
||||
@ -761,7 +674,10 @@ export class CommandCenter {
|
||||
try {
|
||||
document = await workspace.openTextDocument(uri);
|
||||
} catch (error) {
|
||||
await commands.executeCommand('vscode.open', uri, opts);
|
||||
await commands.executeCommand('vscode.open', uri, {
|
||||
...opts,
|
||||
override: arg instanceof Resource && arg.type === Status.BOTH_MODIFIED ? false : undefined
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -801,7 +717,7 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
const HEAD = this.getLeftResource(resource);
|
||||
const HEAD = resource.leftUri;
|
||||
const basename = path.basename(resource.resourceUri.fsPath);
|
||||
const title = `${basename} (HEAD)`;
|
||||
|
||||
@ -819,10 +735,6 @@ export class CommandCenter {
|
||||
|
||||
@command('git.openChange')
|
||||
async openChange(arg?: Resource | Uri, ...resourceStates: SourceControlResourceState[]): Promise<void> {
|
||||
const preserveFocus = arg instanceof Resource;
|
||||
const preview = !(arg instanceof Resource);
|
||||
|
||||
const preserveSelection = arg instanceof Uri || !arg;
|
||||
let resources: Resource[] | undefined = undefined;
|
||||
|
||||
if (arg instanceof Uri) {
|
||||
@ -849,10 +761,33 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
for (const resource of resources) {
|
||||
await this._openResource(resource, preview, preserveFocus, preserveSelection);
|
||||
await resource.openChange();
|
||||
}
|
||||
}
|
||||
|
||||
@command('git.rename', { repository: true })
|
||||
async rename(repository: Repository, fromUri: Uri | undefined): Promise<void> {
|
||||
fromUri = fromUri ?? window.activeTextEditor?.document.uri;
|
||||
|
||||
if (!fromUri) {
|
||||
return;
|
||||
}
|
||||
|
||||
const from = path.relative(repository.root, fromUri.path);
|
||||
let to = await window.showInputBox({
|
||||
value: from,
|
||||
valueSelection: [from.length - path.basename(from).length, from.length]
|
||||
});
|
||||
|
||||
to = to?.trim();
|
||||
|
||||
if (!to) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.move(from, to);
|
||||
}
|
||||
|
||||
@command('git.stage')
|
||||
async stage(...resourceStates: SourceControlResourceState[]): Promise<void> {
|
||||
this.outputChannel.appendLine(`git.stage ${resourceStates.length}`);
|
||||
@ -1018,6 +953,10 @@ export class CommandCenter {
|
||||
|
||||
@command('git.stageChange')
|
||||
async stageChange(uri: Uri, changes: LineChange[], index: number): Promise<void> {
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0];
|
||||
|
||||
if (!textEditor) {
|
||||
@ -1068,6 +1007,10 @@ export class CommandCenter {
|
||||
|
||||
@command('git.revertChange')
|
||||
async revertChange(uri: Uri, changes: LineChange[], index: number): Promise<void> {
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0];
|
||||
|
||||
if (!textEditor) {
|
||||
@ -1397,7 +1340,7 @@ export class CommandCenter {
|
||||
? localize('unsaved files single', "The following file has unsaved changes which won't be included in the commit if you proceed: {0}.\n\nWould you like to save it before committing?", path.basename(documents[0].uri.fsPath))
|
||||
: localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before committing?", documents.length);
|
||||
const saveAndCommit = localize('save and commit', "Save All & Commit");
|
||||
const commit = localize('commit', "Commit Anyway");
|
||||
const commit = localize('commit', "Commit Staged Changes");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, saveAndCommit, commit);
|
||||
|
||||
if (pick === saveAndCommit) {
|
||||
@ -1409,8 +1352,14 @@ export class CommandCenter {
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts) {
|
||||
opts = { all: noStagedChanges };
|
||||
} else if (!opts.all && noStagedChanges && !opts.empty) {
|
||||
opts = { ...opts, all: true };
|
||||
}
|
||||
|
||||
// no changes, and the user has not configured to commit all in this case
|
||||
if (!noUnstagedChanges && noStagedChanges && !enableSmartCommit) {
|
||||
if (!noUnstagedChanges && noStagedChanges && !enableSmartCommit && !opts.empty) {
|
||||
const suggestSmartCommit = config.get<boolean>('suggestSmartCommit') === true;
|
||||
|
||||
if (!suggestSmartCommit) {
|
||||
@ -1434,13 +1383,7 @@ export class CommandCenter {
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts) {
|
||||
opts = { all: noStagedChanges };
|
||||
} else if (!opts.all && noStagedChanges) {
|
||||
opts = { ...opts, all: true };
|
||||
}
|
||||
|
||||
// enable signing of commits if configurated
|
||||
// enable signing of commits if configured
|
||||
opts.signCommit = enableCommitSigning;
|
||||
|
||||
if (config.get<boolean>('alwaysSignOff')) {
|
||||
@ -1458,10 +1401,18 @@ export class CommandCenter {
|
||||
// no staged changes and no tracked unstaged changes
|
||||
|| (noStagedChanges && smartCommitChanges === 'tracked' && repository.workingTreeGroup.resourceStates.every(r => r.type === Status.UNTRACKED))
|
||||
)
|
||||
// amend allows changing only the commit message
|
||||
&& !opts.amend
|
||||
&& !opts.empty
|
||||
) {
|
||||
window.showInformationMessage(localize('no changes', "There are no changes to commit."));
|
||||
return false;
|
||||
const commitAnyway = localize('commit anyway', "Create Empty Commit");
|
||||
const answer = await window.showInformationMessage(localize('no changes', "There are no changes to commit."), commitAnyway);
|
||||
|
||||
if (answer !== commitAnyway) {
|
||||
return false;
|
||||
}
|
||||
|
||||
opts.empty = true;
|
||||
}
|
||||
|
||||
if (opts.noVerify) {
|
||||
@ -1484,9 +1435,9 @@ export class CommandCenter {
|
||||
}
|
||||
}
|
||||
|
||||
const message = await getCommitMessage();
|
||||
let message = await getCommitMessage();
|
||||
|
||||
if (!message) {
|
||||
if (!message && !opts.amend) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1523,7 +1474,7 @@ export class CommandCenter {
|
||||
let value: string | undefined = undefined;
|
||||
|
||||
if (opts && opts.amend && repository.HEAD && repository.HEAD.commit) {
|
||||
value = (await repository.getCommit(repository.HEAD.commit)).message;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const branchName = repository.headShortName;
|
||||
@ -1690,20 +1641,38 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
@command('git.checkout', { repository: true })
|
||||
async checkout(repository: Repository, treeish: string): Promise<boolean> {
|
||||
if (typeof treeish === 'string') {
|
||||
await repository.checkout(treeish);
|
||||
async checkout(repository: Repository, treeish?: string): Promise<boolean> {
|
||||
return this._checkout(repository, { treeish });
|
||||
}
|
||||
|
||||
@command('git.checkoutDetached', { repository: true })
|
||||
async checkoutDetached(repository: Repository, treeish?: string): Promise<boolean> {
|
||||
return this._checkout(repository, { detached: true, treeish });
|
||||
}
|
||||
|
||||
private async _checkout(repository: Repository, opts?: { detached?: boolean, treeish?: string }): Promise<boolean> {
|
||||
if (typeof opts?.treeish === 'string') {
|
||||
await repository.checkout(opts?.treeish, opts);
|
||||
return true;
|
||||
}
|
||||
|
||||
const createBranch = new CreateBranchItem(this);
|
||||
const createBranchFrom = new CreateBranchFromItem(this);
|
||||
const picks = [createBranch, createBranchFrom, ...createCheckoutItems(repository)];
|
||||
const placeHolder = localize('select a ref to checkout', 'Select a ref to checkout');
|
||||
const createBranch = new CreateBranchItem();
|
||||
const createBranchFrom = new CreateBranchFromItem();
|
||||
const checkoutDetached = new CheckoutDetachedItem();
|
||||
const picks: QuickPickItem[] = [];
|
||||
|
||||
if (!opts?.detached) {
|
||||
picks.push(createBranch, createBranchFrom, checkoutDetached);
|
||||
}
|
||||
|
||||
picks.push(...createCheckoutItems(repository));
|
||||
|
||||
const quickpick = window.createQuickPick();
|
||||
quickpick.items = picks;
|
||||
quickpick.placeholder = placeHolder;
|
||||
quickpick.placeholder = opts?.detached
|
||||
? localize('select a ref to checkout detached', 'Select a ref to checkout in detached mode')
|
||||
: localize('select a ref to checkout', 'Select a ref to checkout');
|
||||
|
||||
quickpick.show();
|
||||
|
||||
const choice = await new Promise<QuickPickItem | undefined>(c => quickpick.onDidAccept(() => c(quickpick.activeItems[0])));
|
||||
@ -1717,8 +1686,31 @@ export class CommandCenter {
|
||||
await this._branch(repository, quickpick.value);
|
||||
} else if (choice === createBranchFrom) {
|
||||
await this._branch(repository, quickpick.value, true);
|
||||
} else if (choice === checkoutDetached) {
|
||||
return this._checkout(repository, { detached: true });
|
||||
} else {
|
||||
await (choice as CheckoutItem).run(repository);
|
||||
const item = choice as CheckoutItem;
|
||||
|
||||
try {
|
||||
await item.run(repository, opts);
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode !== GitErrorCodes.DirtyWorkTree) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
const force = localize('force', "Force Checkout");
|
||||
const stash = localize('stashcheckout', "Stash & Checkout");
|
||||
const choice = await window.showWarningMessage(localize('local changes', "Your local changes would be overwritten by checkout."), { modal: true }, force, stash);
|
||||
|
||||
if (choice === force) {
|
||||
await this.cleanAll(repository);
|
||||
await item.run(repository, opts);
|
||||
} else if (choice === stash) {
|
||||
await this.stash(repository);
|
||||
await item.run(repository, opts);
|
||||
await this.stashPopLatest(repository);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1849,8 +1841,8 @@ export class CommandCenter {
|
||||
@command('git.merge', { repository: true })
|
||||
async merge(repository: Repository): Promise<void> {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const checkoutType = config.get<string>('checkoutType') || 'all';
|
||||
const includeRemotes = checkoutType === 'all' || checkoutType === 'remote';
|
||||
const checkoutType = config.get<string | string[]>('checkoutType');
|
||||
const includeRemotes = checkoutType === 'all' || checkoutType === 'remote' || checkoutType?.includes('remote');
|
||||
|
||||
const heads = repository.refs.filter(ref => ref.type === RefType.Head)
|
||||
.filter(ref => ref.name || ref.commit)
|
||||
@ -1874,8 +1866,8 @@ export class CommandCenter {
|
||||
@command('git.rebase', { repository: true })
|
||||
async rebase(repository: Repository): Promise<void> {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const checkoutType = config.get<string>('checkoutType') || 'all';
|
||||
const includeRemotes = checkoutType === 'all' || checkoutType === 'remote';
|
||||
const checkoutType = config.get<string | string[]>('checkoutType');
|
||||
const includeRemotes = checkoutType === 'all' || checkoutType === 'remote' || checkoutType?.includes('remote');
|
||||
|
||||
const heads = repository.refs.filter(ref => ref.type === RefType.Head)
|
||||
.filter(ref => ref.name !== repository.HEAD?.name)
|
||||
@ -2068,7 +2060,7 @@ export class CommandCenter {
|
||||
forcePushMode = config.get<boolean>('useForcePushWithLease') === true ? ForcePushMode.ForceWithLease : ForcePushMode.Force;
|
||||
|
||||
if (config.get<boolean>('confirmForcePush')) {
|
||||
const message = localize('confirm force push', "You are about to force push your changes, this can be destructive and could inadvertedly overwrite changes made by others.\n\nAre you sure to continue?");
|
||||
const message = localize('confirm force push', "You are about to force push your changes, this can be destructive and could inadvertently overwrite changes made by others.\n\nAre you sure to continue?");
|
||||
const yes = localize('ok', "OK");
|
||||
const neverAgain = localize('never ask again', "OK, Don't Ask Again");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes, neverAgain);
|
||||
@ -2086,6 +2078,10 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pushOptions.pushType === PushType.PushTags) {
|
||||
await repository.pushTags(undefined, forcePushMode);
|
||||
}
|
||||
|
||||
if (!repository.HEAD || !repository.HEAD.name) {
|
||||
if (!pushOptions.silent) {
|
||||
window.showWarningMessage(localize('nobranch', "Please check out a branch to push to a remote."));
|
||||
@ -2157,6 +2153,21 @@ export class CommandCenter {
|
||||
await this._push(repository, { pushType: PushType.PushFollowTags, forcePush: true });
|
||||
}
|
||||
|
||||
@command('git.cherryPick', { repository: true })
|
||||
async cherryPick(repository: Repository): Promise<void> {
|
||||
const hash = await window.showInputBox({
|
||||
placeHolder: localize('commit hash', "Commit Hash"),
|
||||
prompt: localize('provide commit hash', "Please provide the commit hash"),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.cherryPick(hash);
|
||||
}
|
||||
|
||||
@command('git.pushTo', { repository: true })
|
||||
async pushTo(repository: Repository): Promise<void> {
|
||||
await this._push(repository, { pushType: PushType.PushTo });
|
||||
@ -2167,6 +2178,11 @@ export class CommandCenter {
|
||||
await this._push(repository, { pushType: PushType.PushTo, forcePush: true });
|
||||
}
|
||||
|
||||
@command('git.pushTags', { repository: true })
|
||||
async pushTags(repository: Repository): Promise<void> {
|
||||
await this._push(repository, { pushType: PushType.PushTags });
|
||||
}
|
||||
|
||||
@command('git.addRemote', { repository: true })
|
||||
async addRemote(repository: Repository): Promise<string | undefined> {
|
||||
const url = await pickRemoteSource(this.model, {
|
||||
@ -2200,6 +2216,7 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
await repository.addRemote(name, url);
|
||||
await repository.fetch(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -2413,7 +2430,45 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
const message = await this.getStashMessage();
|
||||
const config = workspace.getConfiguration('git', Uri.file(repository.root));
|
||||
const promptToSaveFilesBeforeStashing = config.get<'always' | 'staged' | 'never'>('promptToSaveFilesBeforeStash');
|
||||
|
||||
if (promptToSaveFilesBeforeStashing !== 'never') {
|
||||
let documents = workspace.textDocuments
|
||||
.filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath));
|
||||
|
||||
if (promptToSaveFilesBeforeStashing === 'staged' || repository.indexGroup.resourceStates.length > 0) {
|
||||
documents = documents
|
||||
.filter(d => repository.indexGroup.resourceStates.some(s => pathEquals(s.resourceUri.fsPath, d.uri.fsPath)));
|
||||
}
|
||||
|
||||
if (documents.length > 0) {
|
||||
const message = documents.length === 1
|
||||
? localize('unsaved stash files single', "The following file has unsaved changes which won't be included in the stash if you proceed: {0}.\n\nWould you like to save it before stashing?", path.basename(documents[0].uri.fsPath))
|
||||
: localize('unsaved stash files', "There are {0} unsaved files.\n\nWould you like to save them before stashing?", documents.length);
|
||||
const saveAndStash = localize('save and stash', "Save All & Stash");
|
||||
const stash = localize('stash', "Stash Anyway");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, saveAndStash, stash);
|
||||
|
||||
if (pick === saveAndStash) {
|
||||
await Promise.all(documents.map(d => d.save()));
|
||||
} else if (pick !== stash) {
|
||||
return; // do not stash on cancel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let message: string | undefined;
|
||||
|
||||
if (config.get<boolean>('useCommitInputAsStashMessage') && (!repository.sourceControl.commitTemplate || repository.inputBox.value !== repository.sourceControl.commitTemplate)) {
|
||||
message = repository.inputBox.value;
|
||||
}
|
||||
|
||||
message = await window.showInputBox({
|
||||
value: message,
|
||||
prompt: localize('provide stash message', "Optionally provide a stash message"),
|
||||
placeHolder: localize('stash message', "Stash message")
|
||||
});
|
||||
|
||||
if (typeof message === 'undefined') {
|
||||
return;
|
||||
@ -2422,13 +2477,6 @@ export class CommandCenter {
|
||||
await repository.createStash(message, includeUntracked);
|
||||
}
|
||||
|
||||
private async getStashMessage(): Promise<string | undefined> {
|
||||
return await window.showInputBox({
|
||||
prompt: localize('provide stash message', "Optionally provide a stash message"),
|
||||
placeHolder: localize('stash message', "Stash message")
|
||||
});
|
||||
}
|
||||
|
||||
@command('git.stash', { repository: true })
|
||||
stash(repository: Repository): Promise<void> {
|
||||
return this._stash(repository);
|
||||
@ -2496,6 +2544,16 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
// request confirmation for the operation
|
||||
const yes = localize('yes', "Yes");
|
||||
const result = await window.showWarningMessage(
|
||||
localize('sure drop', "Are you sure you want to drop the stash: {0}?", stash.description),
|
||||
yes
|
||||
);
|
||||
if (result !== yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.dropStash(stash.index);
|
||||
}
|
||||
|
||||
@ -2614,6 +2672,31 @@ export class CommandCenter {
|
||||
const outputChannel = this.outputChannel as OutputChannel;
|
||||
choices.set(openOutputChannelChoice, () => outputChannel.show());
|
||||
|
||||
const showCommandOutputChoice = localize('show command output', "Show Command Output");
|
||||
if (err.stderr) {
|
||||
choices.set(showCommandOutputChoice, async () => {
|
||||
const timestamp = new Date().getTime();
|
||||
const uri = Uri.parse(`git-output:/git-error-${timestamp}`);
|
||||
|
||||
let command = 'git';
|
||||
|
||||
if (err.gitArgs) {
|
||||
command = `${command} ${err.gitArgs.join(' ')}`;
|
||||
} else if (err.gitCommand) {
|
||||
command = `${command} ${err.gitCommand}`;
|
||||
}
|
||||
|
||||
this.commandErrors.set(uri, `> ${command}\n${err.stderr}`);
|
||||
|
||||
try {
|
||||
const doc = await workspace.openTextDocument(uri);
|
||||
await window.showTextDocument(doc);
|
||||
} finally {
|
||||
this.commandErrors.delete(uri);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
switch (err.gitErrorCode) {
|
||||
case GitErrorCodes.DirtyWorkTree:
|
||||
message = localize('clean repo', "Please clean your repository working tree before checkout.");
|
||||
|
@ -15,18 +15,18 @@ class GitIgnoreDecorationProvider implements FileDecorationProvider {
|
||||
|
||||
private static Decoration: FileDecoration = { color: new ThemeColor('gitDecoration.ignoredResourceForeground') };
|
||||
|
||||
readonly onDidChange: Event<Uri[]>;
|
||||
readonly onDidChangeFileDecorations: Event<Uri[]>;
|
||||
private queue = new Map<string, { repository: Repository; queue: Map<string, PromiseSource<FileDecoration | undefined>>; }>();
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(private model: Model) {
|
||||
this.onDidChange = fireEvent(anyEvent<any>(
|
||||
this.onDidChangeFileDecorations = fireEvent(anyEvent<any>(
|
||||
filterEvent(workspace.onDidSaveTextDocument, e => /\.gitignore$|\.git\/info\/exclude$/.test(e.uri.path)),
|
||||
model.onDidOpenRepository,
|
||||
model.onDidCloseRepository
|
||||
));
|
||||
|
||||
this.disposables.push(window.registerDecorationProvider(this));
|
||||
this.disposables.push(window.registerFileDecorationProvider(this));
|
||||
}
|
||||
|
||||
async provideFileDecoration(uri: Uri): Promise<FileDecoration | undefined> {
|
||||
@ -93,14 +93,14 @@ class GitDecorationProvider implements FileDecorationProvider {
|
||||
};
|
||||
|
||||
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
|
||||
readonly onDidChange: Event<Uri[]> = this._onDidChangeDecorations.event;
|
||||
readonly onDidChangeFileDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
private decorations = new Map<string, FileDecoration>();
|
||||
|
||||
constructor(private repository: Repository) {
|
||||
this.disposables.push(
|
||||
window.registerDecorationProvider(this),
|
||||
window.registerFileDecorationProvider(this),
|
||||
repository.onDidRunGitStatus(this.onDidRunGitStatus, this)
|
||||
);
|
||||
}
|
||||
|
@ -260,6 +260,7 @@ export interface IGitErrorData {
|
||||
exitCode?: number;
|
||||
gitErrorCode?: string;
|
||||
gitCommand?: string;
|
||||
gitArgs?: string[];
|
||||
}
|
||||
|
||||
export class GitError {
|
||||
@ -271,6 +272,7 @@ export class GitError {
|
||||
exitCode?: number;
|
||||
gitErrorCode?: string;
|
||||
gitCommand?: string;
|
||||
gitArgs?: string[];
|
||||
|
||||
constructor(data: IGitErrorData) {
|
||||
if (data.error) {
|
||||
@ -287,6 +289,7 @@ export class GitError {
|
||||
this.exitCode = data.exitCode;
|
||||
this.gitErrorCode = data.gitErrorCode;
|
||||
this.gitCommand = data.gitCommand;
|
||||
this.gitArgs = data.gitArgs;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
@ -535,7 +538,8 @@ export class Git {
|
||||
stderr: result.stderr,
|
||||
exitCode: result.exitCode,
|
||||
gitErrorCode: getGitErrorCode(result.stderr),
|
||||
gitCommand: args[0]
|
||||
gitCommand: args[0],
|
||||
gitArgs: args
|
||||
}));
|
||||
}
|
||||
|
||||
@ -1295,13 +1299,17 @@ export class Repository {
|
||||
await this.run(['update-index', add, '--cacheinfo', mode, hash, path]);
|
||||
}
|
||||
|
||||
async checkout(treeish: string, paths: string[], opts: { track?: boolean } = Object.create(null)): Promise<void> {
|
||||
async checkout(treeish: string, paths: string[], opts: { track?: boolean, detached?: boolean } = Object.create(null)): Promise<void> {
|
||||
const args = ['checkout', '-q'];
|
||||
|
||||
if (opts.track) {
|
||||
args.push('--track');
|
||||
}
|
||||
|
||||
if (opts.detached) {
|
||||
args.push('--detach');
|
||||
}
|
||||
|
||||
if (treeish) {
|
||||
args.push(treeish);
|
||||
}
|
||||
@ -1317,23 +1325,30 @@ export class Repository {
|
||||
} catch (err) {
|
||||
if (/Please,? commit your changes or stash them/.test(err.stderr || '')) {
|
||||
err.gitErrorCode = GitErrorCodes.DirtyWorkTree;
|
||||
err.gitTreeish = treeish;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async commit(message: string, opts: CommitOptions = Object.create(null)): Promise<void> {
|
||||
const args = ['commit', '--quiet', '--allow-empty-message', '--file', '-'];
|
||||
async commit(message: string | undefined, opts: CommitOptions = Object.create(null)): Promise<void> {
|
||||
const args = ['commit', '--quiet', '--allow-empty-message'];
|
||||
|
||||
if (opts.all) {
|
||||
args.push('--all');
|
||||
}
|
||||
|
||||
if (opts.amend) {
|
||||
if (opts.amend && message) {
|
||||
args.push('--amend');
|
||||
}
|
||||
|
||||
if (opts.amend && !message) {
|
||||
args.push('--amend', '--no-edit');
|
||||
} else {
|
||||
args.push('--file', '-');
|
||||
}
|
||||
|
||||
if (opts.signoff) {
|
||||
args.push('--signoff');
|
||||
}
|
||||
@ -1350,8 +1365,11 @@ export class Repository {
|
||||
args.push('--no-verify');
|
||||
}
|
||||
|
||||
// Stops git from guessing at user/email
|
||||
args.splice(0, 0, '-c', 'user.useConfigOnly=true');
|
||||
|
||||
try {
|
||||
await this.run(args, { input: message || '' });
|
||||
await this.run(args, !opts.amend || message ? { input: message || '' } : {});
|
||||
} catch (commitErr) {
|
||||
await this.handleCommitError(commitErr);
|
||||
}
|
||||
@ -1414,6 +1432,11 @@ export class Repository {
|
||||
await this.run(args);
|
||||
}
|
||||
|
||||
async move(from: string, to: string): Promise<void> {
|
||||
const args = ['mv', from, to];
|
||||
await this.run(args);
|
||||
}
|
||||
|
||||
async setBranchUpstream(name: string, upstream: string): Promise<void> {
|
||||
const args = ['branch', '--set-upstream-to', upstream, name];
|
||||
await this.run(args);
|
||||
@ -1536,9 +1559,11 @@ export class Repository {
|
||||
await this.run(args);
|
||||
}
|
||||
|
||||
async fetch(options: { remote?: string, ref?: string, all?: boolean, prune?: boolean, depth?: number, silent?: boolean } = {}): Promise<void> {
|
||||
async fetch(options: { remote?: string, ref?: string, all?: boolean, prune?: boolean, depth?: number, silent?: boolean, readonly cancellationToken?: CancellationToken } = {}): Promise<void> {
|
||||
const args = ['fetch'];
|
||||
const spawnOptions: SpawnOptions = {};
|
||||
const spawnOptions: SpawnOptions = {
|
||||
cancellationToken: options.cancellationToken,
|
||||
};
|
||||
|
||||
if (options.remote) {
|
||||
args.push(options.remote);
|
||||
@ -1635,7 +1660,7 @@ export class Repository {
|
||||
}
|
||||
}
|
||||
|
||||
async push(remote?: string, name?: string, setUpstream: boolean = false, tags = false, forcePushMode?: ForcePushMode): Promise<void> {
|
||||
async push(remote?: string, name?: string, setUpstream: boolean = false, followTags = false, forcePushMode?: ForcePushMode, tags = false): Promise<void> {
|
||||
const args = ['push'];
|
||||
|
||||
if (forcePushMode === ForcePushMode.ForceWithLease) {
|
||||
@ -1648,10 +1673,14 @@ export class Repository {
|
||||
args.push('-u');
|
||||
}
|
||||
|
||||
if (tags) {
|
||||
if (followTags) {
|
||||
args.push('--follow-tags');
|
||||
}
|
||||
|
||||
if (tags) {
|
||||
args.push('--tags');
|
||||
}
|
||||
|
||||
if (remote) {
|
||||
args.push(remote);
|
||||
}
|
||||
@ -1677,6 +1706,11 @@ export class Repository {
|
||||
}
|
||||
}
|
||||
|
||||
async cherryPick(commitHash: string): Promise<void> {
|
||||
const args = ['cherry-pick', commitHash];
|
||||
await this.run(args);
|
||||
}
|
||||
|
||||
async blame(path: string): Promise<string> {
|
||||
try {
|
||||
const args = ['blame', sanitizePath(path)];
|
||||
@ -1761,11 +1795,17 @@ export class Repository {
|
||||
}
|
||||
}
|
||||
|
||||
getStatus(limit = 5000): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> {
|
||||
getStatus(opts?: { limit?: number, ignoreSubmodules?: boolean }): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> {
|
||||
return new Promise<{ status: IFileStatus[]; didHitLimit: boolean; }>((c, e) => {
|
||||
const parser = new GitStatusParser();
|
||||
const env = { GIT_OPTIONAL_LOCKS: '0' };
|
||||
const child = this.stream(['status', '-z', '-u'], { env });
|
||||
const args = ['status', '-z', '-u'];
|
||||
|
||||
if (opts?.ignoreSubmodules) {
|
||||
args.push('--ignore-submodules');
|
||||
}
|
||||
|
||||
const child = this.stream(args, { env });
|
||||
|
||||
const onExit = (exitCode: number) => {
|
||||
if (exitCode !== 0) {
|
||||
@ -1775,13 +1815,15 @@ export class Repository {
|
||||
stderr,
|
||||
exitCode,
|
||||
gitErrorCode: getGitErrorCode(stderr),
|
||||
gitCommand: 'status'
|
||||
gitCommand: 'status',
|
||||
gitArgs: args
|
||||
}));
|
||||
}
|
||||
|
||||
c({ status: parser.status, didHitLimit: false });
|
||||
};
|
||||
|
||||
const limit = opts?.limit ?? 5000;
|
||||
const onStdoutData = (raw: string) => {
|
||||
parser.update(raw);
|
||||
|
||||
@ -1845,7 +1887,7 @@ export class Repository {
|
||||
args.push('--sort', `-${opts.sort}`);
|
||||
}
|
||||
|
||||
args.push('--format', '%(refname) %(objectname)');
|
||||
args.push('--format', '%(refname) %(objectname) %(*objectname)');
|
||||
|
||||
if (opts?.pattern) {
|
||||
args.push(opts.pattern);
|
||||
@ -1860,12 +1902,12 @@ export class Repository {
|
||||
const fn = (line: string): Ref | null => {
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) {
|
||||
if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40}) ([0-9a-f]{40})?$/.exec(line)) {
|
||||
return { name: match[1], commit: match[2], type: RefType.Head };
|
||||
} else if (match = /^refs\/remotes\/([^/]+)\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) {
|
||||
} else if (match = /^refs\/remotes\/([^/]+)\/([^ ]+) ([0-9a-f]{40}) ([0-9a-f]{40})?$/.exec(line)) {
|
||||
return { name: `${match[1]}/${match[2]}`, commit: match[3], type: RefType.RemoteHead, remote: match[1] };
|
||||
} else if (match = /^refs\/tags\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) {
|
||||
return { name: match[1], commit: match[2], type: RefType.Tag };
|
||||
} else if (match = /^refs\/tags\/([^ ]+) ([0-9a-f]{40}) ([0-9a-f]{40})?$/.exec(line)) {
|
||||
return { name: match[1], commit: match[3] ?? match[2], type: RefType.Tag };
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -59,7 +59,8 @@ class RemoteSourceProviderQuickPick {
|
||||
this.quickpick.items = remoteSources.map(remoteSource => ({
|
||||
label: remoteSource.name,
|
||||
description: remoteSource.description || (typeof remoteSource.url === 'string' ? remoteSource.url : remoteSource.url[0]),
|
||||
remoteSource
|
||||
remoteSource,
|
||||
alwaysShow: true
|
||||
}));
|
||||
}
|
||||
} catch (err) {
|
||||
@ -80,12 +81,30 @@ class RemoteSourceProviderQuickPick {
|
||||
export interface PickRemoteSourceOptions {
|
||||
readonly providerLabel?: (provider: RemoteSourceProvider) => string;
|
||||
readonly urlLabel?: string;
|
||||
readonly providerName?: string;
|
||||
readonly branch?: boolean; // then result is PickRemoteSourceResult
|
||||
}
|
||||
|
||||
export async function pickRemoteSource(model: Model, options: PickRemoteSourceOptions = {}): Promise<string | undefined> {
|
||||
export interface PickRemoteSourceResult {
|
||||
readonly url: string;
|
||||
readonly branch?: string;
|
||||
}
|
||||
|
||||
export async function pickRemoteSource(model: Model, options: PickRemoteSourceOptions & { branch?: false | undefined }): Promise<string | undefined>;
|
||||
export async function pickRemoteSource(model: Model, options: PickRemoteSourceOptions & { branch: true }): Promise<PickRemoteSourceResult | undefined>;
|
||||
export async function pickRemoteSource(model: Model, options: PickRemoteSourceOptions = {}): Promise<string | PickRemoteSourceResult | undefined> {
|
||||
const quickpick = window.createQuickPick<(QuickPickItem & { provider?: RemoteSourceProvider, url?: string })>();
|
||||
quickpick.ignoreFocusOut = true;
|
||||
|
||||
if (options.providerName) {
|
||||
const provider = model.getRemoteProviders()
|
||||
.filter(provider => provider.name === options.providerName)[0];
|
||||
|
||||
if (provider) {
|
||||
return await pickProviderSource(provider, options);
|
||||
}
|
||||
}
|
||||
|
||||
const providers = model.getRemoteProviders()
|
||||
.map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + (options.providerLabel ? options.providerLabel(provider) : provider.name), alwaysShow: true, provider }));
|
||||
|
||||
@ -116,18 +135,48 @@ export async function pickRemoteSource(model: Model, options: PickRemoteSourceOp
|
||||
if (result.url) {
|
||||
return result.url;
|
||||
} else if (result.provider) {
|
||||
const quickpick = new RemoteSourceProviderQuickPick(result.provider);
|
||||
const remote = await quickpick.pick();
|
||||
|
||||
if (remote) {
|
||||
if (typeof remote.url === 'string') {
|
||||
return remote.url;
|
||||
} else if (remote.url.length > 0) {
|
||||
return await window.showQuickPick(remote.url, { ignoreFocusOut: true, placeHolder: localize('pick url', "Choose a URL to clone from.") });
|
||||
}
|
||||
}
|
||||
return await pickProviderSource(result.provider, options);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function pickProviderSource(provider: RemoteSourceProvider, options: PickRemoteSourceOptions = {}): Promise<string | PickRemoteSourceResult | undefined> {
|
||||
const quickpick = new RemoteSourceProviderQuickPick(provider);
|
||||
const remote = await quickpick.pick();
|
||||
|
||||
let url: string | undefined;
|
||||
|
||||
if (remote) {
|
||||
if (typeof remote.url === 'string') {
|
||||
url = remote.url;
|
||||
} else if (remote.url.length > 0) {
|
||||
url = await window.showQuickPick(remote.url, { ignoreFocusOut: true, placeHolder: localize('pick url', "Choose a URL to clone from.") });
|
||||
}
|
||||
}
|
||||
|
||||
if (!url || !options.branch) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (!provider.getBranches) {
|
||||
return { url };
|
||||
}
|
||||
|
||||
const branches = await provider.getBranches(url);
|
||||
|
||||
if (!branches) {
|
||||
return { url };
|
||||
}
|
||||
|
||||
const branch = await window.showQuickPick(branches, {
|
||||
placeHolder: localize('branch name', "Branch name")
|
||||
});
|
||||
|
||||
if (!branch) {
|
||||
return { url };
|
||||
}
|
||||
|
||||
return { url, branch };
|
||||
}
|
||||
|
@ -75,13 +75,21 @@ export class Resource implements SourceControlResourceState {
|
||||
return this._resourceUri;
|
||||
}
|
||||
|
||||
@memoize
|
||||
get leftUri(): Uri | undefined {
|
||||
return this.resources[0];
|
||||
}
|
||||
|
||||
get rightUri(): Uri {
|
||||
return this.resources[1];
|
||||
}
|
||||
|
||||
get command(): Command {
|
||||
return {
|
||||
command: 'git.openResource',
|
||||
title: localize('open', "Open"),
|
||||
arguments: [this]
|
||||
};
|
||||
return this._commandResolver.resolveDefaultCommand(this);
|
||||
}
|
||||
|
||||
@memoize
|
||||
private get resources(): [Uri | undefined, Uri] {
|
||||
return this._commandResolver.getResources(this);
|
||||
}
|
||||
|
||||
get resourceGroupType(): ResourceGroupType { return this._resourceGroupType; }
|
||||
@ -262,12 +270,28 @@ export class Resource implements SourceControlResourceState {
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _commandResolver: ResourceCommandResolver,
|
||||
private _resourceGroupType: ResourceGroupType,
|
||||
private _resourceUri: Uri,
|
||||
private _type: Status,
|
||||
private _useIcons: boolean,
|
||||
private _renameResourceUri?: Uri
|
||||
private _renameResourceUri?: Uri,
|
||||
) { }
|
||||
|
||||
async open(): Promise<void> {
|
||||
const command = this.command;
|
||||
await commands.executeCommand<void>(command.command, ...(command.arguments || []));
|
||||
}
|
||||
|
||||
async openFile(): Promise<void> {
|
||||
const command = this._commandResolver.resolveFileCommand(this);
|
||||
await commands.executeCommand<void>(command.command, ...(command.arguments || []));
|
||||
}
|
||||
|
||||
async openChange(): Promise<void> {
|
||||
const command = this._commandResolver.resolveChangeCommand(this);
|
||||
await commands.executeCommand<void>(command.command, ...(command.arguments || []));
|
||||
}
|
||||
}
|
||||
|
||||
export const enum Operation {
|
||||
@ -292,6 +316,7 @@ export const enum Operation {
|
||||
Fetch = 'Fetch',
|
||||
Pull = 'Pull',
|
||||
Push = 'Push',
|
||||
CherryPick = 'CherryPick',
|
||||
Sync = 'Sync',
|
||||
Show = 'Show',
|
||||
Stage = 'Stage',
|
||||
@ -315,6 +340,8 @@ export const enum Operation {
|
||||
Blame = 'Blame',
|
||||
Log = 'Log',
|
||||
LogFile = 'LogFile',
|
||||
|
||||
Move = 'Move'
|
||||
}
|
||||
|
||||
function isReadOnly(operation: Operation): boolean {
|
||||
@ -550,6 +577,142 @@ class DotGitWatcher implements IFileWatcher {
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceCommandResolver {
|
||||
|
||||
constructor(private repository: Repository) { }
|
||||
|
||||
resolveDefaultCommand(resource: Resource): Command {
|
||||
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
|
||||
const openDiffOnClick = config.get<boolean>('openDiffOnClick', true);
|
||||
return openDiffOnClick ? this.resolveChangeCommand(resource) : this.resolveFileCommand(resource);
|
||||
}
|
||||
|
||||
resolveFileCommand(resource: Resource): Command {
|
||||
return {
|
||||
command: 'vscode.open',
|
||||
title: localize('open', "Open"),
|
||||
arguments: [resource.resourceUri]
|
||||
};
|
||||
}
|
||||
|
||||
resolveChangeCommand(resource: Resource): Command {
|
||||
const title = this.getTitle(resource);
|
||||
|
||||
if (!resource.leftUri) {
|
||||
return {
|
||||
command: 'vscode.open',
|
||||
title: localize('open', "Open"),
|
||||
arguments: [resource.rightUri, { override: resource.type === Status.BOTH_MODIFIED ? false : undefined }, title]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
command: 'vscode.diff',
|
||||
title: localize('open', "Open"),
|
||||
arguments: [resource.leftUri, resource.rightUri, title]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
getResources(resource: Resource): [Uri | undefined, Uri] {
|
||||
for (const submodule of this.repository.submodules) {
|
||||
if (path.join(this.repository.root, submodule.path) === resource.resourceUri.fsPath) {
|
||||
return [undefined, toGitUri(resource.resourceUri, resource.resourceGroupType === ResourceGroupType.Index ? 'index' : 'wt', { submoduleOf: this.repository.root })];
|
||||
}
|
||||
}
|
||||
|
||||
return [this.getLeftResource(resource), this.getRightResource(resource)];
|
||||
}
|
||||
|
||||
private getLeftResource(resource: Resource): Uri | undefined {
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
case Status.INDEX_ADDED:
|
||||
return toGitUri(resource.original, 'HEAD');
|
||||
|
||||
case Status.MODIFIED:
|
||||
case Status.UNTRACKED:
|
||||
return toGitUri(resource.resourceUri, '~');
|
||||
|
||||
case Status.DELETED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
return toGitUri(resource.resourceUri, '~1');
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getRightResource(resource: Resource): Uri {
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_ADDED:
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
return toGitUri(resource.resourceUri, '');
|
||||
|
||||
case Status.INDEX_DELETED:
|
||||
case Status.DELETED:
|
||||
return toGitUri(resource.resourceUri, 'HEAD');
|
||||
|
||||
case Status.DELETED_BY_US:
|
||||
return toGitUri(resource.resourceUri, '~3');
|
||||
|
||||
case Status.DELETED_BY_THEM:
|
||||
return toGitUri(resource.resourceUri, '~2');
|
||||
|
||||
case Status.MODIFIED:
|
||||
case Status.UNTRACKED:
|
||||
case Status.IGNORED:
|
||||
case Status.INTENT_TO_ADD:
|
||||
const uriString = resource.resourceUri.toString();
|
||||
const [indexStatus] = this.repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
|
||||
|
||||
if (indexStatus && indexStatus.renameResourceUri) {
|
||||
return indexStatus.renameResourceUri;
|
||||
}
|
||||
|
||||
return resource.resourceUri;
|
||||
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return resource.resourceUri;
|
||||
}
|
||||
|
||||
throw new Error('Should never happen');
|
||||
}
|
||||
|
||||
private getTitle(resource: Resource): string {
|
||||
const basename = path.basename(resource.resourceUri.fsPath);
|
||||
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
case Status.INDEX_ADDED:
|
||||
return localize('git.title.index', '{0} (Index)', basename);
|
||||
|
||||
case Status.MODIFIED:
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return localize('git.title.workingTree', '{0} (Working Tree)', basename);
|
||||
|
||||
case Status.INDEX_DELETED:
|
||||
case Status.DELETED:
|
||||
return localize('git.title.deleted', '{0} (Deleted)', basename);
|
||||
|
||||
case Status.DELETED_BY_US:
|
||||
return localize('git.title.theirs', '{0} (Theirs)', basename);
|
||||
|
||||
case Status.DELETED_BY_THEM:
|
||||
return localize('git.title.ours', '{0} (Ours)', basename);
|
||||
|
||||
case Status.UNTRACKED:
|
||||
return localize('git.title.untracked', '{0} (Untracked)', basename);
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Repository implements Disposable {
|
||||
|
||||
private _onDidChangeRepository = new EventEmitter<Uri>();
|
||||
@ -680,6 +843,7 @@ export class Repository implements Disposable {
|
||||
private isRepositoryHuge = false;
|
||||
private didWarnAboutLimit = false;
|
||||
|
||||
private resourceCommandResolver = new ResourceCommandResolver(this);
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(
|
||||
@ -746,11 +910,12 @@ export class Repository implements Disposable {
|
||||
onConfigListener(updateIndexGroupVisibility, this, this.disposables);
|
||||
updateIndexGroupVisibility();
|
||||
|
||||
const onConfigListenerForBranchSortOrder = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.branchSortOrder', root));
|
||||
onConfigListenerForBranchSortOrder(this.updateModelState, this, this.disposables);
|
||||
|
||||
const onConfigListenerForUntracked = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.untrackedChanges', root));
|
||||
onConfigListenerForUntracked(this.updateModelState, this, this.disposables);
|
||||
filterEvent(workspace.onDidChangeConfiguration, e =>
|
||||
e.affectsConfiguration('git.branchSortOrder', root)
|
||||
|| e.affectsConfiguration('git.untrackedChanges', root)
|
||||
|| e.affectsConfiguration('git.ignoreSubmodules', root)
|
||||
|| e.affectsConfiguration('git.openDiffOnClick', root)
|
||||
)(this.updateModelState, this, this.disposables);
|
||||
|
||||
const updateInputBoxVisibility = () => {
|
||||
const config = workspace.getConfiguration('git', root);
|
||||
@ -864,6 +1029,12 @@ export class Repository implements Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const path = uri.path;
|
||||
|
||||
if (this.mergeGroup.resourceStates.some(r => r.resourceUri.path === path)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return toGitUri(uri, '', { replaceFileExtension: true });
|
||||
}
|
||||
|
||||
@ -976,7 +1147,7 @@ export class Repository implements Disposable {
|
||||
await this.run(Operation.RevertFiles, () => this.repository.revert('HEAD', resources.map(r => r.fsPath)));
|
||||
}
|
||||
|
||||
async commit(message: string, opts: CommitOptions = Object.create(null)): Promise<void> {
|
||||
async commit(message: string | undefined, opts: CommitOptions = Object.create(null)): Promise<void> {
|
||||
if (this.rebaseCommit) {
|
||||
await this.run(Operation.RebaseContinue, async () => {
|
||||
if (opts.all) {
|
||||
@ -1053,6 +1224,14 @@ export class Repository implements Disposable {
|
||||
await this.run(Operation.RenameBranch, () => this.repository.renameBranch(name));
|
||||
}
|
||||
|
||||
async cherryPick(commitHash: string): Promise<void> {
|
||||
await this.run(Operation.CherryPick, () => this.repository.cherryPick(commitHash));
|
||||
}
|
||||
|
||||
async move(from: string, to: string): Promise<void> {
|
||||
await this.run(Operation.Move, () => this.repository.move(from, to));
|
||||
}
|
||||
|
||||
async getBranch(name: string): Promise<Branch> {
|
||||
return await this.run(Operation.GetBranch, () => this.repository.getBranch(name));
|
||||
}
|
||||
@ -1081,12 +1260,12 @@ export class Repository implements Disposable {
|
||||
await this.run(Operation.DeleteTag, () => this.repository.deleteTag(name));
|
||||
}
|
||||
|
||||
async checkout(treeish: string): Promise<void> {
|
||||
await this.run(Operation.Checkout, () => this.repository.checkout(treeish, []));
|
||||
async checkout(treeish: string, opts?: { detached?: boolean }): Promise<void> {
|
||||
await this.run(Operation.Checkout, () => this.repository.checkout(treeish, [], opts));
|
||||
}
|
||||
|
||||
async checkoutTracking(treeish: string): Promise<void> {
|
||||
await this.run(Operation.CheckoutTracking, () => this.repository.checkout(treeish, [], { track: true }));
|
||||
async checkoutTracking(treeish: string, opts: { detached?: boolean } = {}): Promise<void> {
|
||||
await this.run(Operation.CheckoutTracking, () => this.repository.checkout(treeish, [], { ...opts, track: true }));
|
||||
}
|
||||
|
||||
async findTrackingBranches(upstreamRef: string): Promise<Branch[]> {
|
||||
@ -1119,21 +1298,31 @@ export class Repository implements Disposable {
|
||||
|
||||
@throttle
|
||||
async fetchDefault(options: { silent?: boolean } = {}): Promise<void> {
|
||||
await this.run(Operation.Fetch, () => this.repository.fetch(options));
|
||||
await this._fetch({ silent: options.silent });
|
||||
}
|
||||
|
||||
@throttle
|
||||
async fetchPrune(): Promise<void> {
|
||||
await this.run(Operation.Fetch, () => this.repository.fetch({ prune: true }));
|
||||
await this._fetch({ prune: true });
|
||||
}
|
||||
|
||||
@throttle
|
||||
async fetchAll(): Promise<void> {
|
||||
await this.run(Operation.Fetch, () => this.repository.fetch({ all: true }));
|
||||
await this._fetch({ all: true });
|
||||
}
|
||||
|
||||
async fetch(remote?: string, ref?: string, depth?: number): Promise<void> {
|
||||
await this.run(Operation.Fetch, () => this.repository.fetch({ remote, ref, depth }));
|
||||
await this._fetch({ remote, ref, depth });
|
||||
}
|
||||
|
||||
private async _fetch(options: { remote?: string, ref?: string, all?: boolean, prune?: boolean, depth?: number, silent?: boolean } = {}): Promise<void> {
|
||||
if (!options.prune) {
|
||||
const config = workspace.getConfiguration('git', Uri.file(this.root));
|
||||
const prune = config.get<boolean>('pruneOnFetch');
|
||||
options.prune = prune;
|
||||
}
|
||||
|
||||
await this.run(Operation.Fetch, async () => this.repository.fetch(options));
|
||||
}
|
||||
|
||||
@throttle
|
||||
@ -1169,11 +1358,12 @@ export class Repository implements Disposable {
|
||||
const fetchOnPull = config.get<boolean>('fetchOnPull');
|
||||
const tags = config.get<boolean>('pullTags');
|
||||
|
||||
// When fetchOnPull is enabled, fetch all branches when pulling
|
||||
if (fetchOnPull) {
|
||||
await this.repository.pull(rebase, undefined, undefined, { unshallow, tags });
|
||||
} else {
|
||||
await this.repository.pull(rebase, remote, branch, { unshallow, tags });
|
||||
await this.repository.fetch({ all: true });
|
||||
}
|
||||
|
||||
await this.repository.pull(rebase, remote, branch, { unshallow, tags });
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1199,6 +1389,10 @@ export class Repository implements Disposable {
|
||||
await this.run(Operation.Push, () => this._push(remote, undefined, false, true, forcePushMode));
|
||||
}
|
||||
|
||||
async pushTags(remote?: string, forcePushMode?: ForcePushMode): Promise<void> {
|
||||
await this.run(Operation.Push, () => this._push(remote, undefined, false, false, forcePushMode, true));
|
||||
}
|
||||
|
||||
async blame(path: string): Promise<string> {
|
||||
return await this.run(Operation.Blame, () => this.repository.blame(path));
|
||||
}
|
||||
@ -1229,11 +1423,18 @@ export class Repository implements Disposable {
|
||||
const config = workspace.getConfiguration('git', Uri.file(this.root));
|
||||
const fetchOnPull = config.get<boolean>('fetchOnPull');
|
||||
const tags = config.get<boolean>('pullTags');
|
||||
const followTags = config.get<boolean>('followTagsWhenSync');
|
||||
const supportCancellation = config.get<boolean>('supportCancellation');
|
||||
|
||||
const fn = fetchOnPull
|
||||
? async (cancellationToken?: CancellationToken) => await this.repository.pull(rebase, undefined, undefined, { tags, cancellationToken })
|
||||
: async (cancellationToken?: CancellationToken) => await this.repository.pull(rebase, remoteName, pullBranch, { tags, cancellationToken });
|
||||
const fn = async (cancellationToken?: CancellationToken) => {
|
||||
// When fetchOnPull is enabled, fetch all branches when pulling
|
||||
if (fetchOnPull) {
|
||||
await this.repository.fetch({ all: true, cancellationToken });
|
||||
}
|
||||
|
||||
await this.repository.pull(rebase, remoteName, pullBranch, { tags, cancellationToken });
|
||||
};
|
||||
|
||||
|
||||
if (supportCancellation) {
|
||||
const opts: ProgressOptions = {
|
||||
@ -1256,7 +1457,7 @@ export class Repository implements Disposable {
|
||||
const shouldPush = this.HEAD && (typeof this.HEAD.ahead === 'number' ? this.HEAD.ahead > 0 : true);
|
||||
|
||||
if (shouldPush) {
|
||||
await this._push(remoteName, pushBranch);
|
||||
await this._push(remoteName, pushBranch, false, followTags);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1418,9 +1619,9 @@ export class Repository implements Disposable {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
private async _push(remote?: string, refspec?: string, setUpstream: boolean = false, tags = false, forcePushMode?: ForcePushMode): Promise<void> {
|
||||
private async _push(remote?: string, refspec?: string, setUpstream: boolean = false, followTags = false, forcePushMode?: ForcePushMode, tags = false): Promise<void> {
|
||||
try {
|
||||
await this.repository.push(remote, refspec, setUpstream, tags, forcePushMode);
|
||||
await this.repository.push(remote, refspec, setUpstream, followTags, forcePushMode, tags);
|
||||
} catch (err) {
|
||||
if (!remote || !refspec) {
|
||||
throw err;
|
||||
@ -1518,9 +1719,12 @@ export class Repository implements Disposable {
|
||||
|
||||
@throttle
|
||||
private async updateModelState(): Promise<void> {
|
||||
const { status, didHitLimit } = await this.repository.getStatus();
|
||||
const config = workspace.getConfiguration('git');
|
||||
const scopedConfig = workspace.getConfiguration('git', Uri.file(this.repository.root));
|
||||
const ignoreSubmodules = scopedConfig.get<boolean>('ignoreSubmodules');
|
||||
|
||||
const { status, didHitLimit } = await this.repository.getStatus({ ignoreSubmodules });
|
||||
|
||||
const config = workspace.getConfiguration('git');
|
||||
const shouldIgnore = config.get<boolean>('ignoreLimitWarning') === true;
|
||||
const useIcons = !config.get<boolean>('decorations.enabled', true);
|
||||
this.isRepositoryHuge = didHitLimit;
|
||||
@ -1595,36 +1799,36 @@ export class Repository implements Disposable {
|
||||
|
||||
switch (raw.x + raw.y) {
|
||||
case '??': switch (untrackedChanges) {
|
||||
case 'mixed': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons));
|
||||
case 'separate': return untracked.push(new Resource(ResourceGroupType.Untracked, uri, Status.UNTRACKED, useIcons));
|
||||
case 'mixed': return workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons));
|
||||
case 'separate': return untracked.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.UNTRACKED, useIcons));
|
||||
default: return undefined;
|
||||
}
|
||||
case '!!': switch (untrackedChanges) {
|
||||
case 'mixed': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons));
|
||||
case 'separate': return untracked.push(new Resource(ResourceGroupType.Untracked, uri, Status.IGNORED, useIcons));
|
||||
case 'mixed': return workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons));
|
||||
case 'separate': return untracked.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.IGNORED, useIcons));
|
||||
default: return undefined;
|
||||
}
|
||||
case 'DD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_DELETED, useIcons));
|
||||
case 'AU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_US, useIcons));
|
||||
case 'UD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_THEM, useIcons));
|
||||
case 'UA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_THEM, useIcons));
|
||||
case 'DU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_US, useIcons));
|
||||
case 'AA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_ADDED, useIcons));
|
||||
case 'UU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
|
||||
case 'DD': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.BOTH_DELETED, useIcons));
|
||||
case 'AU': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.ADDED_BY_US, useIcons));
|
||||
case 'UD': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.DELETED_BY_THEM, useIcons));
|
||||
case 'UA': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.ADDED_BY_THEM, useIcons));
|
||||
case 'DU': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.DELETED_BY_US, useIcons));
|
||||
case 'AA': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.BOTH_ADDED, useIcons));
|
||||
case 'UU': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
|
||||
}
|
||||
|
||||
switch (raw.x) {
|
||||
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break;
|
||||
case 'A': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
|
||||
case 'D': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
|
||||
case 'R': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
|
||||
case 'C': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri)); break;
|
||||
case 'M': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break;
|
||||
case 'A': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
|
||||
case 'D': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
|
||||
case 'R': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
|
||||
case 'C': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri)); break;
|
||||
}
|
||||
|
||||
switch (raw.y) {
|
||||
case 'M': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break;
|
||||
case 'D': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break;
|
||||
case 'A': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break;
|
||||
case 'M': workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break;
|
||||
case 'D': workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break;
|
||||
case 'A': workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
@ -200,7 +200,7 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
if (working) {
|
||||
const date = new Date();
|
||||
|
||||
const item = new GitTimelineItem('', index ? '~' : 'HEAD', localize('git.timeline.uncommitedChanges', 'Uncommited Changes'), date.getTime(), 'working', 'git:file:working');
|
||||
const item = new GitTimelineItem('', index ? '~' : 'HEAD', localize('git.timeline.uncommitedChanges', 'Uncommitted Changes'), date.getTime(), 'working', 'git:file:working');
|
||||
// TODO@eamodio: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.description = '';
|
||||
|
@ -40,6 +40,15 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
|
||||
return session;
|
||||
} catch (e) {
|
||||
// If login was cancelled, do not notify user.
|
||||
if (e.message === 'Cancelled') {
|
||||
/* __GDPR__
|
||||
"loginCancelled" : { }
|
||||
*/
|
||||
telemetryReporter.sendTelemetryEvent('loginCancelled');
|
||||
throw e;
|
||||
}
|
||||
|
||||
/* __GDPR__
|
||||
"loginFailed" : { }
|
||||
*/
|
||||
|
@ -180,9 +180,12 @@ export class GitHubAuthenticationProvider {
|
||||
}
|
||||
|
||||
public async logout(id: string) {
|
||||
Logger.info(`Logging out of ${id}`);
|
||||
const sessionIndex = this._sessions.findIndex(session => session.id === id);
|
||||
if (sessionIndex > -1) {
|
||||
this._sessions.splice(sessionIndex, 1);
|
||||
} else {
|
||||
Logger.error('Session not found');
|
||||
}
|
||||
|
||||
await this.storeSessions();
|
||||
|
@ -23,7 +23,7 @@ class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.
|
||||
|
||||
export const uriHandler = new UriEventHandler;
|
||||
|
||||
const onDidManuallyProvideToken = new vscode.EventEmitter<string>();
|
||||
const onDidManuallyProvideToken = new vscode.EventEmitter<string | undefined>();
|
||||
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ export class GitHubServer {
|
||||
|
||||
return Promise.race([
|
||||
existingPromise,
|
||||
promiseFromEvent<string, string>(onDidManuallyProvideToken.event)
|
||||
promiseFromEvent<string | undefined, string>(onDidManuallyProvideToken.event, (token: string | undefined): string => { if (!token) { throw new Error('Cancelled'); } return token; })
|
||||
]).finally(() => {
|
||||
this._pendingStates.delete(scopes);
|
||||
this._codeExchangePromises.delete(scopes);
|
||||
@ -147,7 +147,11 @@ export class GitHubServer {
|
||||
|
||||
public async manuallyProvideToken() {
|
||||
const uriOrToken = await vscode.window.showInputBox({ prompt: 'Token', ignoreFocusOut: true });
|
||||
if (!uriOrToken) { return; }
|
||||
if (!uriOrToken) {
|
||||
onDidManuallyProvideToken.fire(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const uri = vscode.Uri.parse(uriOrToken);
|
||||
if (!uri.scheme || uri.scheme === 'file') { throw new Error; }
|
||||
|
@ -9,6 +9,7 @@ import { API as GitAPI, Repository } from './typings/git';
|
||||
import { getOctokit } from './auth';
|
||||
import { TextEncoder } from 'util';
|
||||
import { basename } from 'path';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@ -57,9 +58,18 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
|
||||
quickpick.show();
|
||||
quickpick.busy = true;
|
||||
|
||||
const octokit = await getOctokit();
|
||||
const user = await octokit.users.getAuthenticated({});
|
||||
const owner = user.data.login;
|
||||
let owner: string;
|
||||
let octokit: Octokit;
|
||||
try {
|
||||
octokit = await getOctokit();
|
||||
const user = await octokit.users.getAuthenticated({});
|
||||
owner = user.data.login;
|
||||
} catch (e) {
|
||||
// User has cancelled sign in
|
||||
quickpick.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
quickpick.busy = false;
|
||||
|
||||
let repo: string | undefined;
|
||||
@ -139,7 +149,7 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
|
||||
new Promise<undefined>(c => quickpick.onDidHide(() => c(undefined)))
|
||||
]);
|
||||
|
||||
if (!result) {
|
||||
if (!result || result.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -192,9 +202,9 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
|
||||
}
|
||||
|
||||
const openInGitHub = 'Open In GitHub';
|
||||
const action = await vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub);
|
||||
|
||||
if (action === openInGitHub) {
|
||||
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
|
||||
}
|
||||
vscode.window.showInformationMessage(`Successfully published the '${owner}/${repo}' repository on GitHub.`, openInGitHub).then(action => {
|
||||
if (action === openInGitHub) {
|
||||
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(githubRepository.html_url));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -40,8 +40,14 @@ async function handlePushError(repository: Repository, remote: Remote, refspec:
|
||||
|
||||
// Issue: what if there's already another `origin` repo?
|
||||
await repository.addRemote('origin', ghRepository.clone_url);
|
||||
await repository.fetch('origin', remoteName);
|
||||
await repository.setBranchUpstream(localName, `origin/${remoteName}`);
|
||||
|
||||
try {
|
||||
await repository.fetch('origin', remoteName);
|
||||
await repository.setBranchUpstream(localName, `origin/${remoteName}`);
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
|
||||
await repository.push('origin', localName, true);
|
||||
|
||||
return [octokit, ghRepository];
|
||||
|
@ -8,6 +8,12 @@ import { getOctokit } from './auth';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import { publishRepository } from './publish';
|
||||
|
||||
function parse(url: string): { owner: string, repo: string } | undefined {
|
||||
const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git/i.exec(url)
|
||||
|| /^git@github\.com:([^/]+)\/([^/]+)\.git/i.exec(url);
|
||||
return (match && { owner: match[1], repo: match[2] }) ?? undefined;
|
||||
}
|
||||
|
||||
function asRemoteSource(raw: any): RemoteSource {
|
||||
return {
|
||||
name: `$(github) ${raw.full_name}`,
|
||||
@ -28,17 +34,30 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {
|
||||
|
||||
async getRemoteSources(query?: string): Promise<RemoteSource[]> {
|
||||
const octokit = await getOctokit();
|
||||
const [fromUser, fromQuery] = await Promise.all([
|
||||
|
||||
if (query) {
|
||||
const repository = parse(query);
|
||||
|
||||
if (repository) {
|
||||
const raw = await octokit.repos.get(repository);
|
||||
return [asRemoteSource(raw.data)];
|
||||
}
|
||||
}
|
||||
|
||||
const all = await Promise.all([
|
||||
this.getUserRemoteSources(octokit, query),
|
||||
this.getQueryRemoteSources(octokit, query)
|
||||
]);
|
||||
|
||||
const userRepos = new Set(fromUser.map(r => r.name));
|
||||
const map = new Map<string, RemoteSource>();
|
||||
|
||||
return [
|
||||
...fromUser,
|
||||
...fromQuery.filter(r => !userRepos.has(r.name))
|
||||
];
|
||||
for (const group of all) {
|
||||
for (const remoteSource of group) {
|
||||
map.set(remoteSource.name, remoteSource);
|
||||
}
|
||||
}
|
||||
|
||||
return [...map.values()];
|
||||
}
|
||||
|
||||
private async getUserRemoteSources(octokit: Octokit, query?: string): Promise<RemoteSource[]> {
|
||||
@ -61,6 +80,35 @@ export class GithubRemoteSourceProvider implements RemoteSourceProvider {
|
||||
return raw.data.items.map(asRemoteSource);
|
||||
}
|
||||
|
||||
async getBranches(url: string): Promise<string[]> {
|
||||
const repository = parse(url);
|
||||
|
||||
if (!repository) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const octokit = await getOctokit();
|
||||
|
||||
const branches: string[] = [];
|
||||
let page = 1;
|
||||
|
||||
while (true) {
|
||||
let res = await octokit.repos.listBranches({ ...repository, per_page: 100, page });
|
||||
|
||||
if (res.data.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
branches.push(...res.data.map(b => b.name));
|
||||
page++;
|
||||
}
|
||||
|
||||
const repo = await octokit.repos.get(repository);
|
||||
const defaultBranch = repo.data.default_branch;
|
||||
|
||||
return branches.sort((a, b) => a === defaultBranch ? -1 : b === defaultBranch ? 1 : 0);
|
||||
}
|
||||
|
||||
publishRepository(repository: Repository): Promise<void> {
|
||||
return publishRepository(this.gitAPI, repository);
|
||||
}
|
||||
|
@ -130,6 +130,7 @@ export interface CommitOptions {
|
||||
signoff?: boolean;
|
||||
signCommit?: boolean;
|
||||
empty?: boolean;
|
||||
noVerify?: boolean;
|
||||
}
|
||||
|
||||
export interface BranchQuery {
|
||||
@ -211,6 +212,7 @@ export interface RemoteSourceProvider {
|
||||
readonly icon?: string; // codicon name
|
||||
readonly supportsQuery?: boolean;
|
||||
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
|
||||
getBranches?(url: string): ProviderResult<string[]>;
|
||||
publishRepository?(repository: Repository): Promise<void>;
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,8 @@ namespace CustomDataChangedNotification {
|
||||
namespace TagCloseRequest {
|
||||
export const type: RequestType<TextDocumentPositionParams, string, any, any> = new RequestType('html/tag');
|
||||
}
|
||||
namespace OnTypeRenameRequest {
|
||||
export const type: RequestType<TextDocumentPositionParams, LspRange[] | null, any, any> = new RequestType('html/onTypeRename');
|
||||
namespace LinkedEditingRequest {
|
||||
export const type: RequestType<TextDocumentPositionParams, LspRange[] | null, any, any> = new RequestType('html/linkedEditing');
|
||||
}
|
||||
|
||||
// experimental: semantic tokens
|
||||
@ -44,7 +44,7 @@ namespace SemanticTokenLegendRequest {
|
||||
}
|
||||
|
||||
namespace SettingIds {
|
||||
export const renameOnType = 'editor.renameOnType';
|
||||
export const linkedRename = 'editor.linkedRename';
|
||||
export const formatEnable = 'html.format.enable';
|
||||
|
||||
}
|
||||
@ -169,10 +169,10 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
|
||||
}
|
||||
});
|
||||
|
||||
disposable = languages.registerOnTypeRenameProvider(documentSelector, {
|
||||
async provideOnTypeRenameRanges(document, position) {
|
||||
disposable = languages.registerLinkedEditingRangeProvider(documentSelector, {
|
||||
async provideLinkedEditingRanges(document, position) {
|
||||
const param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position);
|
||||
return client.sendRequest(OnTypeRenameRequest.type, param).then(response => {
|
||||
return client.sendRequest(LinkedEditingRequest.type, param).then(response => {
|
||||
if (response) {
|
||||
return {
|
||||
ranges: response.map(r => client.protocol2CodeConverter.asRange(r))
|
||||
@ -301,7 +301,7 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
|
||||
const promptForTypeOnRenameKey = 'html.promptForTypeOnRename';
|
||||
const promptForTypeOnRename = extensions.getExtension('formulahendry.auto-rename-tag') !== undefined &&
|
||||
(context.globalState.get(promptForTypeOnRenameKey) !== false) &&
|
||||
!workspace.getConfiguration('editor', { languageId: 'html' }).get('renameOnType');
|
||||
!workspace.getConfiguration('editor', { languageId: 'html' }).get('linkedRename');
|
||||
|
||||
if (promptForTypeOnRename) {
|
||||
const activeEditorListener = window.onDidChangeActiveTextEditor(async e => {
|
||||
@ -309,9 +309,9 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
|
||||
context.globalState.update(promptForTypeOnRenameKey, false);
|
||||
activeEditorListener.dispose();
|
||||
const configure = localize('configureButton', 'Configure');
|
||||
const res = await window.showInformationMessage(localize('renameOnTypeQuestion', 'VS Code now has built-in support for auto-renaming tags. Do you want to enable it?'), configure);
|
||||
const res = await window.showInformationMessage(localize('linkedRenameQuestion', 'VS Code now has built-in support for auto-renaming tags. Do you want to enable it?'), configure);
|
||||
if (res === configure) {
|
||||
commands.executeCommand('workbench.action.openSettings', SettingIds.renameOnType);
|
||||
commands.executeCommand('workbench.action.openSettings', SettingIds.linkedRename);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -24,7 +24,7 @@ export function activate(context: ExtensionContext) {
|
||||
const serverModule = context.asAbsolutePath(serverMain);
|
||||
|
||||
// The debug options for the server
|
||||
const debugOptions = { execArgv: ['--nolazy', '--inspect=6044'] };
|
||||
const debugOptions = { execArgv: ['--nolazy', '--inspect=' + (8000 + Math.round(Math.random() * 999))] };
|
||||
|
||||
// If the extension is launch in debug mode the debug server options are use
|
||||
// Otherwise the run options are used
|
||||
|
@ -138,6 +138,31 @@
|
||||
],
|
||||
"description": "%html.format.wrapAttributes.desc%"
|
||||
},
|
||||
"html.format.wrapAttributesIndentSize": {
|
||||
"type": [
|
||||
"number",
|
||||
"null"
|
||||
],
|
||||
"scope": "resource",
|
||||
"default": null,
|
||||
"description": "%html.format.wrapAttributesIndentSize.desc%"
|
||||
},
|
||||
"html.format.templating": {
|
||||
"type": [
|
||||
"boolean"
|
||||
],
|
||||
"scope": "resource",
|
||||
"default": false,
|
||||
"description": "%html.format.templating.desc%"
|
||||
},
|
||||
"html.format.unformattedContentDelimiter": {
|
||||
"type": [
|
||||
"string"
|
||||
],
|
||||
"scope": "resource",
|
||||
"default": "",
|
||||
"markdownDescription": "%html.format.unformattedContentDelimiter.desc%"
|
||||
},
|
||||
"html.suggest.html5": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
@ -162,6 +187,18 @@
|
||||
"default": true,
|
||||
"description": "%html.autoClosingTags%"
|
||||
},
|
||||
"html.hover.documentation": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%html.hover.documentation%"
|
||||
},
|
||||
"html.hover.references": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%html.hover.references%"
|
||||
},
|
||||
"html.mirrorCursorOnMatchingTag": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
@ -204,7 +241,7 @@
|
||||
"dependencies": {
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
"vscode-languageclient": "7.0.0-next.5.1",
|
||||
"vscode-nls": "^4.1.2"
|
||||
"vscode-nls": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.11.7"
|
||||
|
@ -20,11 +20,16 @@
|
||||
"html.format.wrapAttributes.alignedmultiple": "Wrap when line length is exceeded, align attributes vertically.",
|
||||
"html.format.wrapAttributes.preserve": "Preserve wrapping of attributes",
|
||||
"html.format.wrapAttributes.preservealigned": "Preserve wrapping of attributes but align.",
|
||||
"html.format.templating.desc": "Honor django, erb, handlebars and php templating language tags.",
|
||||
"html.format.unformattedContentDelimiter.desc": "Keep text content together between this string.",
|
||||
"html.format.wrapAttributesIndentSize.desc": "Alignment size when using 'force aligned' and 'aligned multiple' in `#html.format.wrapAttributes#` or `null` to use the default indent size.",
|
||||
"html.suggest.html5.desc": "Controls whether the built-in HTML language support suggests HTML5 tags, properties and values.",
|
||||
"html.trace.server.desc": "Traces the communication between VS Code and the HTML language server.",
|
||||
"html.validate.scripts": "Controls whether the built-in HTML language support validates embedded scripts.",
|
||||
"html.validate.styles": "Controls whether the built-in HTML language support validates embedded styles.",
|
||||
"html.autoClosingTags": "Enable/disable autoclosing of HTML tags.",
|
||||
"html.mirrorCursorOnMatchingTag": "Enable/disable mirroring cursor on matching HTML tag.",
|
||||
"html.mirrorCursorOnMatchingTagDeprecationMessage": "Deprecated in favor of `editor.renameOnType`"
|
||||
"html.mirrorCursorOnMatchingTagDeprecationMessage": "Deprecated in favor of `editor.linkedEditing`",
|
||||
"html.hover.documentation": "Show tag and attribute documentation in hover.",
|
||||
"html.hover.references": "Show references to MDN in hover."
|
||||
}
|
||||
|
@ -9,8 +9,8 @@
|
||||
},
|
||||
"main": "./out/node/htmlServerMain",
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^4.3.5",
|
||||
"vscode-html-languageservice": "^3.1.4",
|
||||
"vscode-css-languageservice": "^4.4.0",
|
||||
"vscode-html-languageservice": "^3.2.0",
|
||||
"vscode-languageserver": "7.0.0-next.3",
|
||||
"vscode-nls": "^5.0.0",
|
||||
"vscode-uri": "^2.1.2"
|
||||
|
@ -33,8 +33,8 @@ namespace CustomDataChangedNotification {
|
||||
namespace TagCloseRequest {
|
||||
export const type: RequestType<TextDocumentPositionParams, string | null, any, any> = new RequestType('html/tag');
|
||||
}
|
||||
namespace OnTypeRenameRequest {
|
||||
export const type: RequestType<TextDocumentPositionParams, Range[] | null, any, any> = new RequestType('html/onTypeRename');
|
||||
namespace LinkedEditingRequest {
|
||||
export const type: RequestType<TextDocumentPositionParams, Range[] | null, any, any> = new RequestType('html/linkedEditing');
|
||||
}
|
||||
|
||||
// experimental: semantic tokens
|
||||
@ -284,7 +284,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
||||
if (!mode || !mode.doComplete) {
|
||||
return { isIncomplete: true, items: [] };
|
||||
}
|
||||
const doComplete = mode.doComplete!;
|
||||
const doComplete = mode.doComplete;
|
||||
|
||||
if (mode.getId() !== 'html') {
|
||||
/* __GDPR__
|
||||
@ -321,8 +321,10 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
||||
const document = documents.get(textDocumentPosition.textDocument.uri);
|
||||
if (document) {
|
||||
const mode = languageModes.getModeAtPosition(document, textDocumentPosition.position);
|
||||
if (mode && mode.doHover) {
|
||||
return mode.doHover(document, textDocumentPosition.position);
|
||||
const doHover = mode?.doHover;
|
||||
if (doHover) {
|
||||
const settings = await getDocumentSettings(document, () => doHover.length > 2);
|
||||
return doHover(document, textDocumentPosition.position, settings);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -508,15 +510,15 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
||||
}, null, `Error while computing rename for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onRequest(OnTypeRenameRequest.type, (params, token) => {
|
||||
connection.onRequest(LinkedEditingRequest.type, (params, token) => {
|
||||
return runSafe(async () => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const pos = params.position;
|
||||
if (pos.character > 0) {
|
||||
const mode = languageModes.getModeAtPosition(document, Position.create(pos.line, pos.character - 1));
|
||||
if (mode && mode.doOnTypeRename) {
|
||||
return mode.doOnTypeRename(document, pos);
|
||||
if (mode && mode.doLinkedEditing) {
|
||||
return mode.doLinkedEditing(document, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
|
||||
import { Stylesheet, LanguageService as CSSLanguageService } from 'vscode-css-languageservice';
|
||||
import { LanguageMode, Workspace, Color, TextDocument, Position, Range, CompletionList, DocumentContext } from './languageModes';
|
||||
import { LanguageMode, Workspace, Color, TextDocument, Position, Range, CompletionList, DocumentContext, Settings } from './languageModes';
|
||||
import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport';
|
||||
|
||||
export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegions: LanguageModelCache<HTMLDocumentRegions>, workspace: Workspace): LanguageMode {
|
||||
@ -25,9 +25,9 @@ export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegio
|
||||
const stylesheet = cssStylesheets.get(embedded);
|
||||
return cssLanguageService.doComplete2(embedded, position, stylesheet, documentContext) || CompletionList.create();
|
||||
},
|
||||
async doHover(document: TextDocument, position: Position) {
|
||||
async doHover(document: TextDocument, position: Position, settings?: Settings) {
|
||||
let embedded = embeddedCSSDocuments.get(document);
|
||||
return cssLanguageService.doHover(embedded, position, cssStylesheets.get(embedded));
|
||||
return cssLanguageService.doHover(embedded, position, cssStylesheets.get(embedded), settings?.html?.hover);
|
||||
},
|
||||
async findDocumentHighlight(document: TextDocument, position: Position) {
|
||||
let embedded = embeddedCSSDocuments.get(document);
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
LanguageService as HTMLLanguageService, HTMLDocument, DocumentContext, FormattingOptions,
|
||||
HTMLFormatConfiguration, SelectionRange,
|
||||
TextDocument, Position, Range, FoldingRange,
|
||||
LanguageMode, Workspace
|
||||
LanguageMode, Workspace, Settings
|
||||
} from './languageModes';
|
||||
|
||||
export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace: Workspace): LanguageMode {
|
||||
@ -31,8 +31,8 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace:
|
||||
let completionList = htmlLanguageService.doComplete2(document, position, htmlDocument, documentContext, options);
|
||||
return completionList;
|
||||
},
|
||||
async doHover(document: TextDocument, position: Position) {
|
||||
return htmlLanguageService.doHover(document, position, htmlDocuments.get(document));
|
||||
async doHover(document: TextDocument, position: Position, settings?: Settings) {
|
||||
return htmlLanguageService.doHover(document, position, htmlDocuments.get(document), settings?.html?.hover);
|
||||
},
|
||||
async findDocumentHighlight(document: TextDocument, position: Position) {
|
||||
return htmlLanguageService.findDocumentHighlights(document, position, htmlDocuments.get(document));
|
||||
@ -80,9 +80,9 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace:
|
||||
const htmlDocument = htmlDocuments.get(document);
|
||||
return htmlLanguageService.findMatchingTagPosition(document, position, htmlDocument);
|
||||
},
|
||||
async doOnTypeRename(document: TextDocument, position: Position) {
|
||||
async doLinkedEditing(document: TextDocument, position: Position) {
|
||||
const htmlDocument = htmlDocuments.get(document);
|
||||
return htmlLanguageService.findOnTypeRenameRanges(document, position, htmlDocument);
|
||||
return htmlLanguageService.findLinkedEditingRanges(document, position, htmlDocument);
|
||||
},
|
||||
dispose() {
|
||||
htmlDocuments.dispose();
|
||||
|
@ -6,7 +6,7 @@
|
||||
import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
|
||||
import {
|
||||
SymbolInformation, SymbolKind, CompletionItem, Location, SignatureHelp, SignatureInformation, ParameterInformation,
|
||||
Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, MarkedString,
|
||||
Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover,
|
||||
DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions, FoldingRange, FoldingRangeKind, SelectionRange,
|
||||
LanguageMode, Settings, SemanticTokenData, Workspace, DocumentContext
|
||||
} from './languageModes';
|
||||
@ -142,10 +142,10 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache<HTMLDocume
|
||||
const jsLanguageService = await host.getLanguageService(jsDocument);
|
||||
let info = jsLanguageService.getQuickInfoAtPosition(jsDocument.uri, jsDocument.offsetAt(position));
|
||||
if (info) {
|
||||
let contents = ts.displayPartsToString(info.displayParts);
|
||||
const contents = ts.displayPartsToString(info.displayParts);
|
||||
return {
|
||||
range: convertRange(jsDocument, info.textSpan),
|
||||
contents: MarkedString.fromPlainText(contents)
|
||||
contents: ['```typescript', contents, '```'].join('\n')
|
||||
};
|
||||
}
|
||||
return null;
|
||||
|
@ -99,7 +99,7 @@ function classifySymbol(symbol: ts.Symbol) {
|
||||
}
|
||||
|
||||
export const enum TokenType {
|
||||
class, enum, interface, namespace, typeParameter, type, parameter, variable, property, function, member, _
|
||||
class, enum, interface, namespace, typeParameter, type, parameter, variable, property, function, method, _
|
||||
}
|
||||
|
||||
export const enum TokenModifier {
|
||||
@ -117,7 +117,7 @@ tokenTypes[TokenType.parameter] = 'parameter';
|
||||
tokenTypes[TokenType.variable] = 'variable';
|
||||
tokenTypes[TokenType.property] = 'property';
|
||||
tokenTypes[TokenType.function] = 'function';
|
||||
tokenTypes[TokenType.member] = 'member';
|
||||
tokenTypes[TokenType.method] = 'method';
|
||||
|
||||
const tokenModifiers: string[] = [];
|
||||
tokenModifiers[TokenModifier.async] = 'async';
|
||||
@ -133,9 +133,9 @@ const tokenFromDeclarationMapping: { [name: string]: TokenType } = {
|
||||
[ts.SyntaxKind.EnumDeclaration]: TokenType.enum,
|
||||
[ts.SyntaxKind.EnumMember]: TokenType.property,
|
||||
[ts.SyntaxKind.ClassDeclaration]: TokenType.class,
|
||||
[ts.SyntaxKind.MethodDeclaration]: TokenType.member,
|
||||
[ts.SyntaxKind.MethodDeclaration]: TokenType.method,
|
||||
[ts.SyntaxKind.FunctionDeclaration]: TokenType.function,
|
||||
[ts.SyntaxKind.MethodSignature]: TokenType.member,
|
||||
[ts.SyntaxKind.MethodSignature]: TokenType.method,
|
||||
[ts.SyntaxKind.GetAccessor]: TokenType.property,
|
||||
[ts.SyntaxKind.PropertySignature]: TokenType.property,
|
||||
[ts.SyntaxKind.InterfaceDeclaration]: TokenType.interface,
|
||||
|
@ -45,10 +45,10 @@ export interface LanguageMode {
|
||||
doValidation?: (document: TextDocument, settings?: Settings) => Promise<Diagnostic[]>;
|
||||
doComplete?: (document: TextDocument, position: Position, documentContext: DocumentContext, settings?: Settings) => Promise<CompletionList>;
|
||||
doResolve?: (document: TextDocument, item: CompletionItem) => Promise<CompletionItem>;
|
||||
doHover?: (document: TextDocument, position: Position) => Promise<Hover | null>;
|
||||
doHover?: (document: TextDocument, position: Position, settings?: Settings) => Promise<Hover | null>;
|
||||
doSignatureHelp?: (document: TextDocument, position: Position) => Promise<SignatureHelp | null>;
|
||||
doRename?: (document: TextDocument, position: Position, newName: string) => Promise<WorkspaceEdit | null>;
|
||||
doOnTypeRename?: (document: TextDocument, position: Position) => Promise<Range[] | null>;
|
||||
doLinkedEditing?: (document: TextDocument, position: Position) => Promise<Range[] | null>;
|
||||
findDocumentHighlight?: (document: TextDocument, position: Position) => Promise<DocumentHighlight[]>;
|
||||
findDocumentSymbols?: (document: TextDocument) => Promise<SymbolInformation[]>;
|
||||
findDocumentLinks?: (document: TextDocument, documentContext: DocumentContext) => Promise<DocumentLink[]>;
|
||||
|
@ -87,8 +87,8 @@ suite('HTML Semantic Tokens', () => {
|
||||
];
|
||||
await assertTokens(input, [
|
||||
t(3, 11, 3, 'function.declaration'), t(3, 15, 2, 'parameter.declaration'),
|
||||
t(4, 11, 3, 'function'), t(4, 15, 4, 'interface'), t(4, 20, 3, 'member'), t(4, 24, 2, 'parameter'),
|
||||
t(6, 6, 6, 'variable'), t(6, 13, 8, 'property'), t(6, 24, 5, 'member'), t(6, 35, 7, 'member'), t(6, 43, 1, 'parameter.declaration'), t(6, 48, 3, 'function'), t(6, 52, 1, 'parameter')
|
||||
t(4, 11, 3, 'function'), t(4, 15, 4, 'interface'), t(4, 20, 3, 'method'), t(4, 24, 2, 'parameter'),
|
||||
t(6, 6, 6, 'variable'), t(6, 13, 8, 'property'), t(6, 24, 5, 'method'), t(6, 35, 7, 'method'), t(6, 43, 1, 'parameter.declaration'), t(6, 48, 3, 'function'), t(6, 52, 1, 'parameter')
|
||||
]);
|
||||
});
|
||||
|
||||
@ -115,9 +115,9 @@ suite('HTML Semantic Tokens', () => {
|
||||
t(3, 8, 1, 'class.declaration'),
|
||||
t(4, 11, 1, 'property.declaration.static'),
|
||||
t(5, 4, 1, 'property.declaration'),
|
||||
t(6, 10, 1, 'member.declaration.async'), t(6, 23, 1, 'class'), t(6, 25, 1, 'property.static'), t(6, 40, 1, 'member.async'),
|
||||
t(6, 10, 1, 'method.declaration.async'), t(6, 23, 1, 'class'), t(6, 25, 1, 'property.static'), t(6, 40, 1, 'method.async'),
|
||||
t(7, 8, 1, 'property.declaration'), t(7, 26, 1, 'property'),
|
||||
t(8, 11, 1, 'member.declaration.static'), t(8, 28, 1, 'class'), t(8, 32, 1, 'property'),
|
||||
t(8, 11, 1, 'method.declaration.static'), t(8, 28, 1, 'class'), t(8, 32, 1, 'property'),
|
||||
]);
|
||||
});
|
||||
|
||||
@ -157,7 +157,7 @@ suite('HTML Semantic Tokens', () => {
|
||||
t(3, 8, 1, 'variable.declaration.readonly'),
|
||||
t(4, 8, 1, 'class.declaration'), t(4, 28, 1, 'property.declaration.static.readonly'), t(4, 42, 3, 'property.declaration.static'), t(4, 47, 3, 'interface'),
|
||||
t(5, 13, 1, 'enum.declaration'), t(5, 17, 1, 'property.declaration.readonly'), t(5, 24, 1, 'property.declaration.readonly'), t(5, 28, 1, 'property.readonly'),
|
||||
t(6, 2, 7, 'variable'), t(6, 10, 3, 'member'), t(6, 14, 1, 'variable.readonly'), t(6, 18, 1, 'class'), t(6, 20, 1, 'property.static.readonly'), t(6, 24, 1, 'class'), t(6, 26, 3, 'property.static'), t(6, 30, 6, 'property.readonly'),
|
||||
t(6, 2, 7, 'variable'), t(6, 10, 3, 'method'), t(6, 14, 1, 'variable.readonly'), t(6, 18, 1, 'class'), t(6, 20, 1, 'property.static.readonly'), t(6, 24, 1, 'class'), t(6, 26, 3, 'property.static'), t(6, 30, 6, 'property.readonly'),
|
||||
]);
|
||||
});
|
||||
|
||||
@ -197,7 +197,7 @@ suite('HTML Semantic Tokens', () => {
|
||||
];
|
||||
await assertTokens(input, [
|
||||
t(3, 11, 1, 'function.declaration'), t(3, 13, 1, 'typeParameter.declaration'), t(3, 16, 2, 'parameter.declaration'), t(3, 20, 1, 'typeParameter'), t(3, 24, 1, 'typeParameter'), t(3, 39, 2, 'parameter'),
|
||||
t(6, 2, 6, 'variable'), t(6, 9, 5, 'member')
|
||||
t(6, 2, 6, 'variable'), t(6, 9, 5, 'method')
|
||||
]);
|
||||
});
|
||||
|
||||
@ -215,7 +215,7 @@ suite('HTML Semantic Tokens', () => {
|
||||
/*9*/'</html>',
|
||||
];
|
||||
await assertTokens(input, [
|
||||
t(3, 2, 6, 'variable'), t(3, 9, 5, 'member')
|
||||
t(3, 2, 6, 'variable'), t(3, 9, 5, 'method')
|
||||
], [Range.create(Position.create(2, 0), Position.create(4, 0))]);
|
||||
|
||||
await assertTokens(input, [
|
||||
|
@ -880,20 +880,20 @@ to-regex-range@^5.0.1:
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
vscode-css-languageservice@^4.3.5:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.3.5.tgz#92f8817057dee7c381df2289aad539c7b553548a"
|
||||
integrity sha512-g9Pjxt9T32jhY0nTOo7WRFm0As27IfdaAxcFa8c7Rml1ZqBn3XXbkExjzxY7sBWYm7I1Tp4dK6UHXHoUQHGwig==
|
||||
vscode-css-languageservice@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.4.0.tgz#a7c5edf3057e707601ca18fa3728784a298513b4"
|
||||
integrity sha512-jWi+297PJUUWTHwlcrZz0zIuEXuHOBJIQMapXmEzbosWGv/gMnNSAMV4hTKnl5wzxvZKZzV6j+WFdrSlKQ5qnw==
|
||||
dependencies:
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "3.16.0-next.2"
|
||||
vscode-nls "^5.0.0"
|
||||
vscode-uri "^2.1.2"
|
||||
|
||||
vscode-html-languageservice@^3.1.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.1.4.tgz#0316dff77ee38dc176f40560cbf55e4f64f4f433"
|
||||
integrity sha512-3M+bm+hNvwQcScVe5/ok9BXvctOiGJ4nlOkkFf+WKSDrYNkarZ/RByKOa1/iylbvZxJUPzbeziembWPe/dMvhw==
|
||||
vscode-html-languageservice@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.2.0.tgz#e92269a04097d87bd23431e3a4e491a27b5447b9"
|
||||
integrity sha512-aLWIoWkvb5HYTVE0kI9/u3P0ZAJGrYOSAAE6L0wqB9radKRtbJNrF9+BjSUFyCgBdNBE/GFExo35LoknQDJrfw==
|
||||
dependencies:
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "3.16.0-next.2"
|
||||
|
@ -71,10 +71,10 @@ vscode-languageserver-types@3.16.0-next.2:
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.2.tgz#940bd15c992295a65eae8ab6b8568a1e8daa3083"
|
||||
integrity sha512-QjXB7CKIfFzKbiCJC4OWC8xUncLsxo19FzGVp/ADFvvi87PlmBSCAtZI5xwGjF5qE0xkLf0jjKUn3DzmpDP52Q==
|
||||
|
||||
vscode-nls@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
||||
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
||||
vscode-nls@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840"
|
||||
integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA==
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
|
@ -35,7 +35,7 @@
|
||||
"prefix": "forin",
|
||||
"body": [
|
||||
"for (const ${1:key} in ${2:object}) {",
|
||||
"\tif (${2:object}.hasOwnProperty(${1:key})) {",
|
||||
"\tif (Object.hasOwnProperty.call(${2:object}, ${1:key})) {",
|
||||
"\t\tconst ${3:element} = ${2:object}[${1:key}];",
|
||||
"\t\t$0",
|
||||
"\t}",
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -254,7 +254,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx",
|
||||
"t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
|
@ -73,6 +73,10 @@ namespace SettingIds {
|
||||
export const maxItemsComputed = 'json.maxItemsComputed';
|
||||
}
|
||||
|
||||
namespace StorageIds {
|
||||
export const maxItemsExceededInformation = 'json.maxItemsExceededInformation';
|
||||
}
|
||||
|
||||
export interface TelemetryReporter {
|
||||
sendTelemetryEvent(eventName: string, properties?: {
|
||||
[key: string]: string;
|
||||
@ -298,8 +302,19 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
|
||||
}
|
||||
}));
|
||||
|
||||
client.onNotification(ResultLimitReachedNotification.type, message => {
|
||||
window.showInformationMessage(`${message}\n${localize('configureLimit', 'Use setting \'{0}\' to configure the limit.', SettingIds.maxItemsComputed)}`);
|
||||
client.onNotification(ResultLimitReachedNotification.type, async message => {
|
||||
const shouldPrompt = context.globalState.get<boolean>(StorageIds.maxItemsExceededInformation) !== false;
|
||||
if (shouldPrompt) {
|
||||
const ok = localize('ok', "Ok");
|
||||
const openSettings = localize('goToSetting', 'Open Settings');
|
||||
const neverAgain = localize('yes never again', "Don't Show Again");
|
||||
const pick = await window.showInformationMessage(`${message}\n${localize('configureLimit', 'Use setting \'{0}\' to configure the limit.', SettingIds.maxItemsComputed)}`, ok, openSettings, neverAgain);
|
||||
if (pick === neverAgain) {
|
||||
await context.globalState.update(StorageIds.maxItemsExceededInformation, false);
|
||||
} else if (pick === openSettings) {
|
||||
await commands.executeCommand('workbench.action.openSettings', SettingIds.maxItemsComputed);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function updateFormatterRegistration() {
|
||||
@ -315,6 +330,8 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
|
||||
range: client.code2ProtocolConverter.asRange(range),
|
||||
options: client.code2ProtocolConverter.asFormattingOptions(options)
|
||||
};
|
||||
params.options.insertFinalNewline = workspace.getConfiguration('files', document).get('insertFinalNewline');
|
||||
|
||||
return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then(
|
||||
client.protocol2CodeConverter.asTextEdits,
|
||||
(error) => {
|
||||
|
@ -25,7 +25,7 @@ export function activate(context: ExtensionContext) {
|
||||
const serverModule = context.asAbsolutePath(serverMain);
|
||||
|
||||
// The debug options for the server
|
||||
const debugOptions = { execArgv: ['--nolazy', '--inspect=6044'] };
|
||||
const debugOptions = { execArgv: ['--nolazy', '--inspect=' + (6000 + Math.round(Math.random() * 999))] };
|
||||
|
||||
// If the extension is launch in debug mode the debug server options are use
|
||||
// Otherwise the run options are used
|
||||
|
@ -127,10 +127,10 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"request-light": "^0.3.0",
|
||||
"request-light": "^0.4.0",
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
"vscode-languageclient": "7.0.0-next.5.1",
|
||||
"vscode-nls": "^4.1.2"
|
||||
"vscode-nls": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.11.7"
|
||||
|
@ -13,5 +13,6 @@
|
||||
"json.schemaResolutionErrorMessage": "Unable to resolve schema.",
|
||||
"json.clickToRetry": "Click to retry.",
|
||||
"json.maxItemsComputed.desc": "The maximum number of outline symbols and folding regions computed (limited for performance reasons).",
|
||||
"json.maxItemsExceededInformation.desc": "Show notification when exceeding the maximum number of outline symbols and folding regions.",
|
||||
"json.enableSchemaDownload.desc": "When enabled, JSON schemas can be fetched from http and https locations."
|
||||
}
|
||||
|
@ -12,9 +12,9 @@
|
||||
},
|
||||
"main": "./out/node/jsonServerMain",
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^2.2.1",
|
||||
"request-light": "^0.3.0",
|
||||
"vscode-json-languageservice": "^3.9.1",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"request-light": "^0.4.0",
|
||||
"vscode-json-languageservice": "^3.11.0",
|
||||
"vscode-languageserver": "7.0.0-next.3",
|
||||
"vscode-uri": "^2.1.2"
|
||||
},
|
||||
|
@ -141,7 +141,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
||||
colorProvider: {},
|
||||
foldingRangeProvider: true,
|
||||
selectionRangeProvider: true,
|
||||
definitionProvider: true
|
||||
documentLinkProvider: {}
|
||||
};
|
||||
|
||||
return { capabilities };
|
||||
@ -481,15 +481,15 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
||||
}, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onDefinition((params, token) => {
|
||||
connection.onDocumentLinks((params, token) => {
|
||||
return runSafeAsync(async () => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
return languageService.findDefinition(document, params.position, jsonDocument);
|
||||
return languageService.findLinks(document, jsonDocument);
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while computing definitions for ${params.textDocument.uri}`, token);
|
||||
}, [], `Error while computing links for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
// Listen on the connection
|
||||
|
@ -61,36 +61,31 @@ https-proxy-agent@^2.2.4:
|
||||
agent-base "^4.3.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
jsonc-parser@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc"
|
||||
integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==
|
||||
|
||||
jsonc-parser@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342"
|
||||
integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==
|
||||
jsonc-parser@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22"
|
||||
integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
request-light@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.3.0.tgz#04daa783e7f0a70392328dda4b546f3e27845f2d"
|
||||
integrity sha512-xlVlZVT0ZvCT+c3zm3SjeFCzchoQxsUUmx5fkal0I6RIDJK+lmb1UYyKJ7WM4dTfnzHP4ElWwAf8Dli8c0/tVA==
|
||||
request-light@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.4.0.tgz#c6b91ef00b18cb0de75d2127e55b3a2c9f7f90f9"
|
||||
integrity sha512-fimzjIVw506FBZLspTAXHdpvgvQebyjpNyLRd0e6drPPRq7gcrROeGWRyF81wLqFg5ijPgnOQbmfck5wdTqpSA==
|
||||
dependencies:
|
||||
http-proxy-agent "^2.1.0"
|
||||
https-proxy-agent "^2.2.4"
|
||||
vscode-nls "^4.1.1"
|
||||
vscode-nls "^4.1.2"
|
||||
|
||||
vscode-json-languageservice@^3.9.1:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.9.1.tgz#f72b581f8cd2bd9b47445ccf8b0ddcde6aba7483"
|
||||
integrity sha512-oJkknkdCVitQ5XPSRa0weHjUxt8eSCptaL+MBQQlRsa6Nb8XnEY0S5wYnLUFHzEvKzwt01/LKk8LdOixWEXkNA==
|
||||
vscode-json-languageservice@^3.11.0:
|
||||
version "3.11.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.11.0.tgz#ad574b36c4346bd7830f1d34b5a5213d3af8d232"
|
||||
integrity sha512-QxI+qV97uD7HHOCjh3MrM1TfbdwmTXrMckri5Tus1/FQiG3baDZb2C9Y0y8QThs7PwHYBIQXcAc59ZveCRZKPA==
|
||||
dependencies:
|
||||
jsonc-parser "^2.3.1"
|
||||
jsonc-parser "^3.0.0"
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "3.16.0-next.2"
|
||||
vscode-nls "^5.0.0"
|
||||
@ -126,10 +121,10 @@ vscode-languageserver@7.0.0-next.3:
|
||||
dependencies:
|
||||
vscode-languageserver-protocol "3.16.0-next.4"
|
||||
|
||||
vscode-nls@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
|
||||
integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A==
|
||||
vscode-nls@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
||||
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
||||
|
||||
vscode-nls@^5.0.0:
|
||||
version "5.0.0"
|
||||
|
@ -94,14 +94,14 @@ ms@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
|
||||
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
|
||||
|
||||
request-light@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.3.0.tgz#04daa783e7f0a70392328dda4b546f3e27845f2d"
|
||||
integrity sha512-xlVlZVT0ZvCT+c3zm3SjeFCzchoQxsUUmx5fkal0I6RIDJK+lmb1UYyKJ7WM4dTfnzHP4ElWwAf8Dli8c0/tVA==
|
||||
request-light@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.4.0.tgz#c6b91ef00b18cb0de75d2127e55b3a2c9f7f90f9"
|
||||
integrity sha512-fimzjIVw506FBZLspTAXHdpvgvQebyjpNyLRd0e6drPPRq7gcrROeGWRyF81wLqFg5ijPgnOQbmfck5wdTqpSA==
|
||||
dependencies:
|
||||
http-proxy-agent "^2.1.0"
|
||||
https-proxy-agent "^2.2.4"
|
||||
vscode-nls "^4.1.1"
|
||||
vscode-nls "^4.1.2"
|
||||
|
||||
semver@^5.3.0:
|
||||
version "5.5.0"
|
||||
@ -146,16 +146,16 @@ vscode-languageserver-types@3.16.0-next.2:
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.2.tgz#940bd15c992295a65eae8ab6b8568a1e8daa3083"
|
||||
integrity sha512-QjXB7CKIfFzKbiCJC4OWC8xUncLsxo19FzGVp/ADFvvi87PlmBSCAtZI5xwGjF5qE0xkLf0jjKUn3DzmpDP52Q==
|
||||
|
||||
vscode-nls@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
|
||||
integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A==
|
||||
|
||||
vscode-nls@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
||||
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
||||
|
||||
vscode-nls@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840"
|
||||
integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA==
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
|
@ -14,4 +14,4 @@
|
||||
}
|
||||
],
|
||||
"version": 1
|
||||
}
|
||||
}
|
@ -33,8 +33,7 @@
|
||||
],
|
||||
"filenames": [
|
||||
"composer.lock",
|
||||
".watchmanconfig",
|
||||
".ember-cli"
|
||||
".watchmanconfig"
|
||||
],
|
||||
"mimetypes": [
|
||||
"application/json",
|
||||
@ -57,6 +56,9 @@
|
||||
".hintrc",
|
||||
".babelrc"
|
||||
],
|
||||
"filenames": [
|
||||
".ember-cli"
|
||||
],
|
||||
"configuration": "./language-configuration.json"
|
||||
}
|
||||
],
|
||||
|
@ -210,4 +210,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -210,4 +210,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,8 +3,47 @@
|
||||
"lineComment": "#"
|
||||
},
|
||||
"brackets": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"]
|
||||
[
|
||||
"{",
|
||||
"}"
|
||||
],
|
||||
[
|
||||
"[",
|
||||
"]"
|
||||
],
|
||||
[
|
||||
"(",
|
||||
")"
|
||||
]
|
||||
],
|
||||
"autoClosingPairs": [
|
||||
[
|
||||
"{",
|
||||
"}"
|
||||
],
|
||||
[
|
||||
"[",
|
||||
"]"
|
||||
],
|
||||
[
|
||||
"(",
|
||||
")"
|
||||
],
|
||||
{
|
||||
"open": "'",
|
||||
"close": "'",
|
||||
"notIn": [
|
||||
"string",
|
||||
"comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"open": "\"",
|
||||
"close": "\"",
|
||||
"notIn": [
|
||||
"string",
|
||||
"comment"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,19 @@
|
||||
],
|
||||
"license": "TextMate Bundle License",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"name": "microsoft/vscode-markdown-tm-grammar",
|
||||
"repositoryUrl": "https://github.com/microsoft/vscode-markdown-tm-grammar",
|
||||
"commitHash": "11cf764606cb2cde54badb5d0e5a0758a8871c4b"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "0.0.0"
|
||||
}
|
||||
],
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,11 @@
|
||||
"body": ["1. ${1:first}", "2. ${2:second}", "3. ${3:third}", "$0"],
|
||||
"description": "Insert ordered list"
|
||||
},
|
||||
"Insert definition list": {
|
||||
"prefix": "definition list",
|
||||
"body": ["${1:term}", ": ${2:definition}", "$0"],
|
||||
"description": "Insert definition list"
|
||||
},
|
||||
"Insert horizontal rule": {
|
||||
"prefix": "horizontal rule",
|
||||
"body": "----------\n",
|
||||
@ -83,5 +88,5 @@
|
||||
"prefix": "strikethrough",
|
||||
"body": "~~${1:${TM_SELECTED_TEXT}}~~",
|
||||
"description": "Insert strikethrough"
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/4be9cb335581f3559166c319607dac9100103083",
|
||||
"version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/f051a36bd9713dd722cbe1bdde9c8240d12f00b4",
|
||||
"name": "Markdown",
|
||||
"scopeName": "text.html.markdown",
|
||||
"patterns": [
|
||||
@ -2190,9 +2190,18 @@
|
||||
},
|
||||
"13": {
|
||||
"name": "punctuation.definition.string.end.markdown"
|
||||
},
|
||||
"14": {
|
||||
"name": "string.other.link.description.title.markdown"
|
||||
},
|
||||
"15": {
|
||||
"name": "punctuation.definition.string.begin.markdown"
|
||||
},
|
||||
"16": {
|
||||
"name": "punctuation.definition.string.end.markdown"
|
||||
}
|
||||
},
|
||||
"match": "(?x)\n \\s* # Leading whitespace\n (\\[)([^]]+?)(\\])(:) # Reference name\n [ \\t]* # Optional whitespace\n (<?)(\\S+?)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in quotes…\n | ((\").+?(\")) # or in parens.\n )? # Title is optional\n \\s* # Optional whitespace\n $\n",
|
||||
"match": "(?x)\n \\s* # Leading whitespace\n (\\[)([^]]+?)(\\])(:) # Reference name\n [ \\t]* # Optional whitespace\n (<?)(\\S+?)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in double quotes…\n | ((').+?(')) # or in single quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n $\n",
|
||||
"name": "meta.link.reference.def.markdown"
|
||||
},
|
||||
"list_paragraph": {
|
||||
@ -2453,10 +2462,19 @@
|
||||
"name": "punctuation.definition.string.markdown"
|
||||
},
|
||||
"15": {
|
||||
"name": "string.other.link.description.title.markdown"
|
||||
},
|
||||
"16": {
|
||||
"name": "punctuation.definition.string.markdown"
|
||||
},
|
||||
"17": {
|
||||
"name": "punctuation.definition.string.markdown"
|
||||
},
|
||||
"18": {
|
||||
"name": "punctuation.definition.metadata.markdown"
|
||||
}
|
||||
},
|
||||
"match": "(?x)\n (\\!\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)(\\S+?)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n",
|
||||
"match": "(?x)\n (\\!\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)(\\S+?)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in double quotes…\n | ((').+?(')) # or in single quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n",
|
||||
"name": "meta.image.inline.markdown"
|
||||
},
|
||||
"image-ref": {
|
||||
@ -2616,10 +2634,19 @@
|
||||
"name": "punctuation.definition.string.end.markdown"
|
||||
},
|
||||
"16": {
|
||||
"name": "string.other.link.description.title.markdown"
|
||||
},
|
||||
"17": {
|
||||
"name": "punctuation.definition.string.begin.markdown"
|
||||
},
|
||||
"18": {
|
||||
"name": "punctuation.definition.string.end.markdown"
|
||||
},
|
||||
"19": {
|
||||
"name": "punctuation.definition.metadata.markdown"
|
||||
}
|
||||
},
|
||||
"match": "(?x)\n (\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)((?<url>(?>[^\\s()]+)|\\(\\g<url>*\\))*)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n",
|
||||
"match": "(?x)\n (\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)((?<url>(?>[^\\s()]+)|\\(\\g<url>*\\))*)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in double quotes…\n | ((').+?(')) # or in single quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n",
|
||||
"name": "meta.link.inline.markdown"
|
||||
},
|
||||
"link-ref": {
|
||||
|
@ -154,15 +154,13 @@ table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table > thead > tr > th {
|
||||
th {
|
||||
text-align: left;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
table > thead > tr > th,
|
||||
table > thead > tr > td,
|
||||
table > tbody > tr > th,
|
||||
table > tbody > tr > td {
|
||||
th,
|
||||
td {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
@ -217,22 +215,22 @@ pre code {
|
||||
border-color: rgb(0, 0, 0);
|
||||
}
|
||||
|
||||
.vscode-light table > thead > tr > th {
|
||||
.vscode-light th {
|
||||
border-color: rgba(0, 0, 0, 0.69);
|
||||
}
|
||||
|
||||
.vscode-dark table > thead > tr > th {
|
||||
.vscode-dark th {
|
||||
border-color: rgba(255, 255, 255, 0.69);
|
||||
}
|
||||
|
||||
.vscode-light h1,
|
||||
.vscode-light hr,
|
||||
.vscode-light table > tbody > tr + tr > td {
|
||||
.vscode-light td {
|
||||
border-color: rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.vscode-dark h1,
|
||||
.vscode-dark hr,
|
||||
.vscode-dark table > tbody > tr + tr > td {
|
||||
.vscode-dark td {
|
||||
border-color: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
@ -324,7 +324,7 @@
|
||||
"watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose"
|
||||
},
|
||||
"dependencies": {
|
||||
"highlight.js": "9.15.10",
|
||||
"highlight.js": "10.1.2",
|
||||
"markdown-it": "^10.0.0",
|
||||
"markdown-it-front-matter": "^0.2.1",
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
|
@ -12,10 +12,18 @@ import { TableOfContentsProvider } from '../tableOfContentsProvider';
|
||||
import { isMarkdownFile } from '../util/file';
|
||||
|
||||
|
||||
type UriComponents = {
|
||||
readonly scheme?: string;
|
||||
readonly path: string;
|
||||
readonly fragment?: string;
|
||||
readonly authority?: string;
|
||||
readonly query?: string;
|
||||
};
|
||||
|
||||
export interface OpenDocumentLinkArgs {
|
||||
readonly path: {};
|
||||
readonly parts: UriComponents;
|
||||
readonly fragment: string;
|
||||
readonly fromResource: {};
|
||||
readonly fromResource: UriComponents;
|
||||
}
|
||||
|
||||
enum OpenMarkdownLinks {
|
||||
@ -32,7 +40,7 @@ export class OpenDocumentLinkCommand implements Command {
|
||||
path: vscode.Uri,
|
||||
fragment: string,
|
||||
): vscode.Uri {
|
||||
const toJson = (uri: vscode.Uri) => {
|
||||
const toJson = (uri: vscode.Uri): UriComponents => {
|
||||
return {
|
||||
scheme: uri.scheme,
|
||||
authority: uri.authority,
|
||||
@ -42,7 +50,7 @@ export class OpenDocumentLinkCommand implements Command {
|
||||
};
|
||||
};
|
||||
return vscode.Uri.parse(`command:${OpenDocumentLinkCommand.id}?${encodeURIComponent(JSON.stringify(<OpenDocumentLinkArgs>{
|
||||
path: toJson(path),
|
||||
parts: toJson(path),
|
||||
fragment,
|
||||
fromResource: toJson(fromResource),
|
||||
}))}`);
|
||||
@ -56,36 +64,58 @@ export class OpenDocumentLinkCommand implements Command {
|
||||
return OpenDocumentLinkCommand.execute(this.engine, args);
|
||||
}
|
||||
|
||||
public static async execute(engine: MarkdownEngine, args: OpenDocumentLinkArgs) {
|
||||
public static async execute(engine: MarkdownEngine, args: OpenDocumentLinkArgs): Promise<void> {
|
||||
const fromResource = vscode.Uri.parse('').with(args.fromResource);
|
||||
const targetResource = vscode.Uri.parse('').with(args.path);
|
||||
|
||||
const targetResource = reviveUri(args.parts);
|
||||
|
||||
const column = this.getViewColumn(fromResource);
|
||||
try {
|
||||
return await this.tryOpen(engine, targetResource, args, column);
|
||||
} catch {
|
||||
if (extname(targetResource.path) === '') {
|
||||
return this.tryOpen(engine, targetResource.with({ path: targetResource.path + '.md' }), args, column);
|
||||
}
|
||||
await vscode.commands.executeCommand('vscode.open', targetResource, column);
|
||||
return undefined;
|
||||
|
||||
const didOpen = await this.tryOpen(engine, targetResource, args, column);
|
||||
if (didOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (extname(targetResource.path) === '') {
|
||||
await this.tryOpen(engine, targetResource.with({ path: targetResource.path + '.md' }), args, column);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static async tryOpen(engine: MarkdownEngine, resource: vscode.Uri, args: OpenDocumentLinkArgs, column: vscode.ViewColumn) {
|
||||
if (vscode.window.activeTextEditor && isMarkdownFile(vscode.window.activeTextEditor.document)) {
|
||||
if (vscode.window.activeTextEditor.document.uri.fsPath === resource.fsPath) {
|
||||
return this.tryRevealLine(engine, vscode.window.activeTextEditor, args.fragment);
|
||||
private static async tryOpen(engine: MarkdownEngine, resource: vscode.Uri, args: OpenDocumentLinkArgs, column: vscode.ViewColumn): Promise<boolean> {
|
||||
const tryUpdateForActiveFile = async (): Promise<boolean> => {
|
||||
if (vscode.window.activeTextEditor && isMarkdownFile(vscode.window.activeTextEditor.document)) {
|
||||
if (vscode.window.activeTextEditor.document.uri.fsPath === resource.fsPath) {
|
||||
await this.tryRevealLine(engine, vscode.window.activeTextEditor, args.fragment);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (await tryUpdateForActiveFile()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let stat: vscode.FileStat;
|
||||
try {
|
||||
stat = await vscode.workspace.fs.stat(resource);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
const stat = await vscode.workspace.fs.stat(resource);
|
||||
if (stat.type === vscode.FileType.Directory) {
|
||||
return vscode.commands.executeCommand('revealInExplorer', resource);
|
||||
await vscode.commands.executeCommand('revealInExplorer', resource);
|
||||
return true;
|
||||
}
|
||||
|
||||
return vscode.workspace.openTextDocument(resource)
|
||||
.then(document => vscode.window.showTextDocument(document, column))
|
||||
.then(editor => this.tryRevealLine(engine, editor, args.fragment));
|
||||
try {
|
||||
await vscode.commands.executeCommand('vscode.open', resource, column);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tryUpdateForActiveFile();
|
||||
}
|
||||
|
||||
private static getViewColumn(resource: vscode.Uri): vscode.ViewColumn {
|
||||
@ -101,7 +131,7 @@ export class OpenDocumentLinkCommand implements Command {
|
||||
}
|
||||
|
||||
private static async tryRevealLine(engine: MarkdownEngine, editor: vscode.TextEditor, fragment?: string) {
|
||||
if (editor && fragment) {
|
||||
if (fragment) {
|
||||
const toc = new TableOfContentsProvider(engine, editor.document);
|
||||
const entry = await toc.lookup(fragment);
|
||||
if (entry) {
|
||||
@ -122,6 +152,12 @@ export class OpenDocumentLinkCommand implements Command {
|
||||
}
|
||||
}
|
||||
|
||||
function reviveUri(parts: any) {
|
||||
if (parts.scheme === 'file') {
|
||||
return vscode.Uri.file(parts.path);
|
||||
}
|
||||
return vscode.Uri.parse('').with(parts);
|
||||
}
|
||||
|
||||
export async function resolveLinkToMarkdownFile(path: string): Promise<vscode.Uri | undefined> {
|
||||
try {
|
||||
|
@ -65,19 +65,6 @@ function getWorkspaceFolder(document: vscode.TextDocument) {
|
||||
|| vscode.workspace.workspaceFolders?.[0]?.uri;
|
||||
}
|
||||
|
||||
function matchAll(
|
||||
pattern: RegExp,
|
||||
text: string
|
||||
): Array<RegExpMatchArray> {
|
||||
const out: RegExpMatchArray[] = [];
|
||||
pattern.lastIndex = 0;
|
||||
let match: RegExpMatchArray | null;
|
||||
while ((match = pattern.exec(text))) {
|
||||
out.push(match);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function extractDocumentLink(
|
||||
document: vscode.TextDocument,
|
||||
pre: number,
|
||||
@ -103,7 +90,7 @@ function extractDocumentLink(
|
||||
}
|
||||
|
||||
export default class LinkProvider implements vscode.DocumentLinkProvider {
|
||||
private readonly linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*)(([^\s\(\)]|\(\S*?\))+)\s*(".*?")?\)/g;
|
||||
private readonly linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*)(([^\s\(\)]|\([^\s\(\)]*?\))+)\s*(".*?")?\)/g;
|
||||
private readonly referenceLinkPattern = /(\[((?:\\\]|[^\]])+)\]\[\s*?)([^\s\]]*?)\]/g;
|
||||
private readonly definitionPattern = /^([\t ]*\[(?!\^)((?:\\\]|[^\]])+)\]:\s*)(\S+)/gm;
|
||||
|
||||
@ -124,7 +111,7 @@ export default class LinkProvider implements vscode.DocumentLinkProvider {
|
||||
document: vscode.TextDocument,
|
||||
): vscode.DocumentLink[] {
|
||||
const results: vscode.DocumentLink[] = [];
|
||||
for (const match of matchAll(this.linkPattern, text)) {
|
||||
for (const match of text.matchAll(this.linkPattern)) {
|
||||
const matchImage = match[4] && extractDocumentLink(document, match[3].length + 1, match[4], match.index);
|
||||
if (matchImage) {
|
||||
results.push(matchImage);
|
||||
@ -144,7 +131,7 @@ export default class LinkProvider implements vscode.DocumentLinkProvider {
|
||||
const results: vscode.DocumentLink[] = [];
|
||||
|
||||
const definitions = this.getDefinitions(text, document);
|
||||
for (const match of matchAll(this.referenceLinkPattern, text)) {
|
||||
for (const match of text.matchAll(this.referenceLinkPattern)) {
|
||||
let linkStart: vscode.Position;
|
||||
let linkEnd: vscode.Position;
|
||||
let reference = match[3];
|
||||
@ -190,7 +177,7 @@ export default class LinkProvider implements vscode.DocumentLinkProvider {
|
||||
|
||||
private getDefinitions(text: string, document: vscode.TextDocument) {
|
||||
const out = new Map<string, { link: string, linkRange: vscode.Range }>();
|
||||
for (const match of matchAll(this.definitionPattern, text)) {
|
||||
for (const match of text.matchAll(this.definitionPattern)) {
|
||||
const pre = match[1];
|
||||
const reference = match[2];
|
||||
const link = match[3].trim();
|
||||
|
@ -7,7 +7,6 @@ import { Token } from 'markdown-it';
|
||||
import * as vscode from 'vscode';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { TableOfContentsProvider } from '../tableOfContentsProvider';
|
||||
import { flatten } from '../util/arrays';
|
||||
|
||||
const rangeLimit = 5000;
|
||||
|
||||
@ -27,7 +26,7 @@ export default class MarkdownFoldingProvider implements vscode.FoldingRangeProvi
|
||||
this.getHeaderFoldingRanges(document),
|
||||
this.getBlockFoldingRanges(document)
|
||||
]);
|
||||
return flatten(foldables).slice(0, rangeLimit);
|
||||
return foldables.flat().slice(0, rangeLimit);
|
||||
}
|
||||
|
||||
private async getRegions(document: vscode.TextDocument): Promise<vscode.FoldingRange[]> {
|
||||
|
@ -408,7 +408,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
}
|
||||
}
|
||||
|
||||
OpenDocumentLinkCommand.execute(this.engine, { path: hrefPath, fragment, fromResource: this.resource.toJSON() });
|
||||
OpenDocumentLinkCommand.execute(this.engine, { parts: { path: hrefPath }, fragment, fromResource: this.resource.toJSON() });
|
||||
}
|
||||
|
||||
//#region WebviewResourceProvider
|
||||
|
@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Token } from 'markdown-it';
|
||||
import * as vscode from 'vscode';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
@ -15,7 +14,7 @@ export default class MarkdownSmartSelect implements vscode.SelectionRangeProvide
|
||||
) { }
|
||||
|
||||
public async provideSelectionRanges(document: vscode.TextDocument, positions: vscode.Position[], _token: vscode.CancellationToken): Promise<vscode.SelectionRange[] | undefined> {
|
||||
let promises = await Promise.all(positions.map((position) => {
|
||||
const promises = await Promise.all(positions.map((position) => {
|
||||
return this.provideSelectionRange(document, position, _token);
|
||||
}));
|
||||
return promises.filter(item => item !== undefined) as vscode.SelectionRange[];
|
||||
@ -24,54 +23,206 @@ export default class MarkdownSmartSelect implements vscode.SelectionRangeProvide
|
||||
private async provideSelectionRange(document: vscode.TextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise<vscode.SelectionRange | undefined> {
|
||||
const headerRange = await this.getHeaderSelectionRange(document, position);
|
||||
const blockRange = await this.getBlockSelectionRange(document, position, headerRange);
|
||||
return blockRange ? blockRange : headerRange ? headerRange : undefined;
|
||||
const inlineRange = await this.getInlineSelectionRange(document, position, blockRange);
|
||||
return inlineRange || blockRange || headerRange;
|
||||
}
|
||||
private async getInlineSelectionRange(document: vscode.TextDocument, position: vscode.Position, blockRange?: vscode.SelectionRange): Promise<vscode.SelectionRange | undefined> {
|
||||
return createInlineRange(document, position, blockRange);
|
||||
}
|
||||
|
||||
private async getBlockSelectionRange(document: vscode.TextDocument, position: vscode.Position, headerRange?: vscode.SelectionRange): Promise<vscode.SelectionRange | undefined> {
|
||||
|
||||
const tokens = await this.engine.parse(document);
|
||||
|
||||
let blockTokens = getTokensForPosition(tokens, position);
|
||||
const blockTokens = getBlockTokensForPosition(tokens, position, headerRange);
|
||||
|
||||
if (blockTokens.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let parentRange = headerRange ? headerRange : createBlockRange(document, position.line, blockTokens.shift());
|
||||
let currentRange: vscode.SelectionRange | undefined;
|
||||
let currentRange: vscode.SelectionRange | undefined = headerRange ? headerRange : createBlockRange(blockTokens.shift()!, document, position.line);
|
||||
|
||||
for (const token of blockTokens) {
|
||||
currentRange = createBlockRange(document, position.line, token, parentRange);
|
||||
if (currentRange) {
|
||||
parentRange = currentRange;
|
||||
}
|
||||
}
|
||||
if (currentRange) {
|
||||
return currentRange;
|
||||
} else {
|
||||
return parentRange;
|
||||
}
|
||||
}
|
||||
|
||||
private async getHeaderSelectionRange(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.SelectionRange | undefined> {
|
||||
const tocProvider = new TableOfContentsProvider(this.engine, document);
|
||||
const toc = await tocProvider.getToc();
|
||||
|
||||
let headerInfo = getHeadersForPosition(toc, position);
|
||||
|
||||
let headers = headerInfo.headers;
|
||||
|
||||
let parentRange: vscode.SelectionRange | undefined;
|
||||
let currentRange: vscode.SelectionRange | undefined;
|
||||
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
currentRange = createHeaderRange(i === headers.length - 1, headerInfo.headerOnThisLine, headers[i], parentRange, getFirstChildHeader(document, headers[i], toc));
|
||||
if (currentRange && currentRange.parent) {
|
||||
parentRange = currentRange;
|
||||
}
|
||||
for (let i = 0; i < blockTokens.length; i++) {
|
||||
currentRange = createBlockRange(blockTokens[i], document, position.line, currentRange);
|
||||
}
|
||||
return currentRange;
|
||||
}
|
||||
|
||||
private async getHeaderSelectionRange(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.SelectionRange | undefined> {
|
||||
|
||||
const tocProvider = new TableOfContentsProvider(this.engine, document);
|
||||
const toc = await tocProvider.getToc();
|
||||
|
||||
const headerInfo = getHeadersForPosition(toc, position);
|
||||
|
||||
const headers = headerInfo.headers;
|
||||
|
||||
let currentRange: vscode.SelectionRange | undefined;
|
||||
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
currentRange = createHeaderRange(headers[i], i === headers.length - 1, headerInfo.headerOnThisLine, currentRange, getFirstChildHeader(document, headers[i], toc));
|
||||
}
|
||||
return currentRange;
|
||||
}
|
||||
}
|
||||
|
||||
function getHeadersForPosition(toc: TocEntry[], position: vscode.Position): { headers: TocEntry[], headerOnThisLine: boolean } {
|
||||
const enclosingHeaders = toc.filter(header => header.location.range.start.line <= position.line && header.location.range.end.line >= position.line);
|
||||
const sortedHeaders = enclosingHeaders.sort((header1, header2) => (header1.line - position.line) - (header2.line - position.line));
|
||||
const onThisLine = toc.find(header => header.line === position.line) !== undefined;
|
||||
return {
|
||||
headers: sortedHeaders,
|
||||
headerOnThisLine: onThisLine
|
||||
};
|
||||
}
|
||||
|
||||
function createHeaderRange(header: TocEntry, isClosestHeaderToPosition: boolean, onHeaderLine: boolean, parent?: vscode.SelectionRange, startOfChildRange?: vscode.Position): vscode.SelectionRange | undefined {
|
||||
const range = header.location.range;
|
||||
const contentRange = new vscode.Range(range.start.translate(1), range.end);
|
||||
if (onHeaderLine && isClosestHeaderToPosition && startOfChildRange) {
|
||||
// selection was made on this header line, so select header and its content until the start of its first child
|
||||
// then all of its content
|
||||
return new vscode.SelectionRange(range.with(undefined, startOfChildRange), new vscode.SelectionRange(range, parent));
|
||||
} else if (onHeaderLine && isClosestHeaderToPosition) {
|
||||
// selection was made on this header line and no children so expand to all of its content
|
||||
return new vscode.SelectionRange(range, parent);
|
||||
} else if (isClosestHeaderToPosition && startOfChildRange) {
|
||||
// selection was made within content and has child so select content
|
||||
// of this header then all content then header
|
||||
return new vscode.SelectionRange(contentRange.with(undefined, startOfChildRange), new vscode.SelectionRange(contentRange, (new vscode.SelectionRange(range, parent))));
|
||||
} else {
|
||||
// not on this header line so select content then header
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent));
|
||||
}
|
||||
}
|
||||
|
||||
function getBlockTokensForPosition(tokens: Token[], position: vscode.Position, parent?: vscode.SelectionRange): Token[] {
|
||||
const enclosingTokens = tokens.filter(token => token.map && (token.map[0] <= position.line && token.map[1] > position.line) && (!parent || (token.map[0] >= parent.range.start.line && token.map[1] <= parent.range.end.line + 1)) && isBlockElement(token));
|
||||
if (enclosingTokens.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const sortedTokens = enclosingTokens.sort((token1, token2) => (token2.map[1] - token2.map[0]) - (token1.map[1] - token1.map[0]));
|
||||
return sortedTokens;
|
||||
}
|
||||
|
||||
function createBlockRange(block: Token, document: vscode.TextDocument, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
if (block.type === 'fence') {
|
||||
return createFencedRange(block, cursorLine, document, parent);
|
||||
} else {
|
||||
let startLine = document.lineAt(block.map[0]).isEmptyOrWhitespace ? block.map[0] + 1 : block.map[0];
|
||||
let endLine = startLine === block.map[1] ? block.map[1] : block.map[1] - 1;
|
||||
if (block.type === 'paragraph_open' && block.map[1] - block.map[0] === 2) {
|
||||
startLine = endLine = cursorLine;
|
||||
} else if (isList(block) && document.lineAt(endLine).isEmptyOrWhitespace) {
|
||||
endLine = endLine - 1;
|
||||
}
|
||||
const range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text?.length ?? 0);
|
||||
if (parent?.range.contains(range) && !parent.range.isEqual(range)) {
|
||||
return new vscode.SelectionRange(range, parent);
|
||||
} else if (parent?.range.isEqual(range)) {
|
||||
return parent;
|
||||
} else {
|
||||
return new vscode.SelectionRange(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createInlineRange(document: vscode.TextDocument, cursorPosition: vscode.Position, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
const lineText = document.lineAt(cursorPosition.line).text;
|
||||
const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent);
|
||||
const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent);
|
||||
let comboSelection: vscode.SelectionRange | undefined;
|
||||
if (boldSelection && italicSelection && !boldSelection.range.isEqual(italicSelection.range)) {
|
||||
if (boldSelection.range.contains(italicSelection.range)) {
|
||||
comboSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, boldSelection);
|
||||
} else if (italicSelection.range.contains(boldSelection.range)) {
|
||||
comboSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, italicSelection);
|
||||
}
|
||||
}
|
||||
const linkSelection = createLinkRange(lineText, cursorPosition.character, cursorPosition.line, comboSelection || boldSelection || italicSelection || parent);
|
||||
const inlineCodeBlockSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, false, linkSelection || parent);
|
||||
return inlineCodeBlockSelection || linkSelection || comboSelection || boldSelection || italicSelection;
|
||||
}
|
||||
|
||||
function createFencedRange(token: Token, cursorLine: number, document: vscode.TextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange {
|
||||
const startLine = token.map[0];
|
||||
const endLine = token.map[1] - 1;
|
||||
const onFenceLine = cursorLine === startLine || cursorLine === endLine;
|
||||
const fenceRange = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length);
|
||||
const contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(startLine + 1, 0, endLine - 1, document.lineAt(endLine - 1).text.length) : undefined;
|
||||
if (contentRange) {
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange, parent));
|
||||
} else {
|
||||
if (parent?.range.isEqual(fenceRange)) {
|
||||
return parent;
|
||||
} else {
|
||||
return new vscode.SelectionRange(fenceRange, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createBoldRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
const regex = /(?:^|(?<=\s))(?:\*\*\s*([^*]+)(?:\*\s*([^*]+)\s*?\*)*([^*]+)\s*?\*\*)/g;
|
||||
const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
if (matches.length > 0) {
|
||||
// should only be one match, so select first and index 0 contains the entire match
|
||||
const bold = matches[0][0];
|
||||
const startIndex = lineText.indexOf(bold);
|
||||
const cursorOnStars = cursorChar === startIndex || cursorChar === startIndex + 1 || cursorChar === startIndex + bold.length || cursorChar === startIndex + bold.length - 1;
|
||||
const contentAndStars = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + bold.length), parent);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 2, cursorLine, startIndex + bold.length - 2), contentAndStars);
|
||||
return cursorOnStars ? contentAndStars : content;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function createOtherInlineRange(lineText: string, cursorChar: number, cursorLine: number, isItalic: boolean, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
const regex = isItalic ? /(?:^|(?<=\s))(?:\*\s*([^*]+)(?:\*\*\s*([^*]+)\s*?\*\*)*([^*]+)\s*?\*)/g : /\`[^\`]*\`/g;
|
||||
const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
if (matches.length > 0) {
|
||||
// should only be one match, so select first and index 0 contains the entire match
|
||||
const match = matches[0][0];
|
||||
const startIndex = lineText.indexOf(match);
|
||||
const cursorOnType = cursorChar === startIndex || cursorChar === startIndex + match.length;
|
||||
const contentAndType = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + match.length), parent);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 1, cursorLine, startIndex + match.length - 1), contentAndType);
|
||||
return cursorOnType ? contentAndType : content;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function createLinkRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
const regex = /(\[[^\(\)]*\])(\([^\[\]]*\))/g;
|
||||
const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length > cursorChar);
|
||||
|
||||
if (matches.length > 0) {
|
||||
// should only be one match, so select first and index 0 contains the entire match, so match = [text](url)
|
||||
const link = matches[0][0];
|
||||
const linkRange = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(link), cursorLine, lineText.indexOf(link) + link.length), parent);
|
||||
|
||||
const linkText = matches[0][1];
|
||||
const url = matches[0][2];
|
||||
|
||||
// determine if cursor is within [text] or (url) in order to know which should be selected
|
||||
const nearestType = cursorChar >= lineText.indexOf(linkText) && cursorChar < lineText.indexOf(linkText) + linkText.length ? linkText : url;
|
||||
|
||||
const indexOfType = lineText.indexOf(nearestType);
|
||||
// determine if cursor is on a bracket or paren and if so, return the [content] or (content), skipping over the content range
|
||||
const cursorOnType = cursorChar === indexOfType || cursorChar === indexOfType + nearestType.length;
|
||||
|
||||
const contentAndNearestType = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType, cursorLine, indexOfType + nearestType.length), linkRange);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType + 1, cursorLine, indexOfType + nearestType.length - 1), contentAndNearestType);
|
||||
return cursorOnType ? contentAndNearestType : content;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isList(token: Token): boolean {
|
||||
return token.type ? ['ordered_list_open', 'list_item_open', 'bullet_list_open'].includes(token.type) : false;
|
||||
}
|
||||
|
||||
function isBlockElement(token: Token): boolean {
|
||||
return !['list_item_close', 'paragraph_close', 'bullet_list_close', 'inline', 'heading_close', 'heading_open'].includes(token.type);
|
||||
}
|
||||
|
||||
function getFirstChildHeader(document: vscode.TextDocument, header?: TocEntry, toc?: TocEntry[]): vscode.Position | undefined {
|
||||
@ -80,159 +231,9 @@ function getFirstChildHeader(document: vscode.TextDocument, header?: TocEntry, t
|
||||
let children = toc.filter(t => header.location.range.contains(t.location.range) && t.location.range.start.line > header.location.range.start.line).sort((t1, t2) => t1.line - t2.line);
|
||||
if (children.length > 0) {
|
||||
childRange = children[0].location.range.start;
|
||||
let lineText = document.lineAt(childRange.line - 1).text;
|
||||
const lineText = document.lineAt(childRange.line - 1).text;
|
||||
return childRange ? childRange.translate(-1, lineText.length) : undefined;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTokensForPosition(tokens: Token[], position: vscode.Position): Token[] {
|
||||
let enclosingTokens = tokens.filter(token => token.map && (token.map[0] <= position.line && token.map[1] > position.line) && isBlockElement(token));
|
||||
|
||||
if (enclosingTokens.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let sortedTokens = enclosingTokens.sort((token1, token2) => (token2.map[1] - token2.map[0]) - (token1.map[1] - token1.map[0]));
|
||||
return sortedTokens;
|
||||
}
|
||||
|
||||
function getHeadersForPosition(toc: TocEntry[], position: vscode.Position): { headers: TocEntry[], headerOnThisLine: boolean } {
|
||||
let enclosingHeaders = toc.filter(header => header.location.range.start.line <= position.line && header.location.range.end.line >= position.line);
|
||||
let sortedHeaders = enclosingHeaders.sort((header1, header2) => (header1.line - position.line) - (header2.line - position.line));
|
||||
let onThisLine = toc.find(header => header.line === position.line) !== undefined;
|
||||
return {
|
||||
headers: sortedHeaders,
|
||||
headerOnThisLine: onThisLine
|
||||
};
|
||||
}
|
||||
|
||||
function isBlockElement(token: Token): boolean {
|
||||
return !['list_item_close', 'paragraph_close', 'bullet_list_close', 'inline', 'heading_close', 'heading_open'].includes(token.type);
|
||||
}
|
||||
|
||||
function createHeaderRange(isClosestHeaderToPosition: boolean, onHeaderLine: boolean, header?: TocEntry, parent?: vscode.SelectionRange, childStart?: vscode.Position): vscode.SelectionRange | undefined {
|
||||
if (header) {
|
||||
let contentRange = new vscode.Range(header.location.range.start.translate(1), header.location.range.end);
|
||||
let headerPlusContentRange = header.location.range;
|
||||
let partialContentRange = childStart && isClosestHeaderToPosition ? contentRange.with(undefined, childStart) : undefined;
|
||||
if (onHeaderLine && isClosestHeaderToPosition && childStart) {
|
||||
return new vscode.SelectionRange(header.location.range.with(undefined, childStart), new vscode.SelectionRange(header.location.range, parent));
|
||||
} else if (onHeaderLine && isClosestHeaderToPosition) {
|
||||
return new vscode.SelectionRange(header.location.range, parent);
|
||||
} else if (parent && parent.range.contains(headerPlusContentRange)) {
|
||||
if (partialContentRange) {
|
||||
return new vscode.SelectionRange(partialContentRange, new vscode.SelectionRange(contentRange, (new vscode.SelectionRange(headerPlusContentRange, parent))));
|
||||
} else {
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(headerPlusContentRange, parent));
|
||||
}
|
||||
} else if (partialContentRange) {
|
||||
return new vscode.SelectionRange(partialContentRange, new vscode.SelectionRange(contentRange, (new vscode.SelectionRange(headerPlusContentRange))));
|
||||
} else {
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(headerPlusContentRange));
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function createBlockRange(document: vscode.TextDocument, cursorLine: number, block?: Token, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
if (block) {
|
||||
if (block.type === 'fence') {
|
||||
return createFencedRange(block, cursorLine, document, parent);
|
||||
} else {
|
||||
let startLine = document.lineAt(block.map[0]).isEmptyOrWhitespace ? block.map[0] + 1 : block.map[0];
|
||||
let endLine = startLine !== block.map[1] && isList(block.type) ? block.map[1] - 1 : block.map[1];
|
||||
let startPos = new vscode.Position(startLine, 0);
|
||||
let endPos = new vscode.Position(endLine, getEndCharacter(document, startLine, endLine));
|
||||
let range = new vscode.Range(startPos, endPos);
|
||||
if (parent && parent.range.contains(range) && !parent.range.isEqual(range)) {
|
||||
return new vscode.SelectionRange(range, parent);
|
||||
} else if (parent) {
|
||||
if (rangeLinesEqual(range, parent.range)) {
|
||||
return range.end.character > parent.range.end.character ? new vscode.SelectionRange(range) : parent;
|
||||
} else if (parent.range.end.line + 1 === range.end.line) {
|
||||
let adjustedRange = new vscode.Range(range.start, range.end.translate(-1, parent.range.end.character));
|
||||
if (adjustedRange.isEqual(parent.range)) {
|
||||
return parent;
|
||||
} else {
|
||||
return new vscode.SelectionRange(adjustedRange, parent);
|
||||
}
|
||||
} else if (parent.range.end.line === range.end.line) {
|
||||
let adjustedRange = new vscode.Range(parent.range.start, range.end.translate(undefined, parent.range.end.character));
|
||||
if (adjustedRange.isEqual(parent.range)) {
|
||||
return parent;
|
||||
} else {
|
||||
return new vscode.SelectionRange(adjustedRange, parent.parent);
|
||||
}
|
||||
} else {
|
||||
return parent;
|
||||
}
|
||||
} else {
|
||||
return new vscode.SelectionRange(range);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function createFencedRange(token: Token, cursorLine: number, document: vscode.TextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange {
|
||||
const startLine = token.map[0];
|
||||
const endLine = token.map[1] - 1;
|
||||
let onFenceLine = cursorLine === startLine || cursorLine === endLine;
|
||||
let fenceRange = new vscode.Range(new vscode.Position(startLine, 0), new vscode.Position(endLine, document.lineAt(endLine).text.length));
|
||||
let contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(new vscode.Position(startLine + 1, 0), new vscode.Position(endLine - 1, getEndCharacter(document, startLine + 1, endLine))) : undefined;
|
||||
if (parent && contentRange) {
|
||||
if (parent.range.contains(fenceRange) && !parent.range.isEqual(fenceRange)) {
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange, parent));
|
||||
} else if (parent.range.isEqual(fenceRange)) {
|
||||
return new vscode.SelectionRange(contentRange, parent);
|
||||
} else if (rangeLinesEqual(fenceRange, parent.range)) {
|
||||
let revisedRange = fenceRange.end.character > parent.range.end.character ? fenceRange : parent.range;
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(revisedRange, getRealParent(parent, revisedRange)));
|
||||
} else if (parent.range.end.line === fenceRange.end.line) {
|
||||
parent.range.end.translate(undefined, fenceRange.end.character);
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange, parent));
|
||||
}
|
||||
} else if (contentRange) {
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange));
|
||||
} else if (parent) {
|
||||
if (parent.range.contains(fenceRange) && !parent.range.isEqual(fenceRange)) {
|
||||
return new vscode.SelectionRange(fenceRange, parent);
|
||||
} else if (parent.range.isEqual(fenceRange)) {
|
||||
return parent;
|
||||
} else if (rangeLinesEqual(fenceRange, parent.range)) {
|
||||
let revisedRange = fenceRange.end.character > parent.range.end.character ? fenceRange : parent.range;
|
||||
return new vscode.SelectionRange(revisedRange, parent.parent);
|
||||
} else if (parent.range.end.line === fenceRange.end.line) {
|
||||
parent.range.end.translate(undefined, fenceRange.end.character);
|
||||
return new vscode.SelectionRange(fenceRange, parent);
|
||||
}
|
||||
}
|
||||
return new vscode.SelectionRange(fenceRange, parent);
|
||||
}
|
||||
|
||||
function isList(type: string): boolean {
|
||||
return type ? ['ordered_list_open', 'list_item_open', 'bullet_list_open'].includes(type) : false;
|
||||
}
|
||||
|
||||
function getEndCharacter(document: vscode.TextDocument, startLine: number, endLine: number): number {
|
||||
let startLength = document.lineAt(startLine).text ? document.lineAt(startLine).text.length : 0;
|
||||
let endLength = document.lineAt(startLine).text ? document.lineAt(startLine).text.length : 0;
|
||||
let endChar = Math.max(startLength, endLength);
|
||||
return startLine !== endLine ? 0 : endChar;
|
||||
}
|
||||
|
||||
function getRealParent(parent: vscode.SelectionRange, range: vscode.Range) {
|
||||
let currentParent: vscode.SelectionRange | undefined = parent;
|
||||
while (currentParent && !currentParent.range.contains(range)) {
|
||||
currentParent = currentParent.parent;
|
||||
}
|
||||
return currentParent;
|
||||
}
|
||||
|
||||
function rangeLinesEqual(range: vscode.Range, parent: vscode.Range) {
|
||||
return range.start.line === parent.start.line && range.end.line === parent.end.line;
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import { isMarkdownFile } from '../util/file';
|
||||
import { Lazy, lazy } from '../util/lazy';
|
||||
import MDDocumentSymbolProvider from './documentSymbolProvider';
|
||||
import { SkinnyTextDocument, SkinnyTextLine } from '../tableOfContentsProvider';
|
||||
import { flatten } from '../util/arrays';
|
||||
|
||||
export interface WorkspaceMarkdownDocumentProvider {
|
||||
getAllMarkdownDocuments(): Thenable<Iterable<SkinnyTextDocument>>;
|
||||
@ -136,7 +135,7 @@ export default class MarkdownWorkspaceSymbolProvider extends Disposable implemen
|
||||
}
|
||||
|
||||
const allSymbolsSets = await Promise.all(Array.from(this._symbolCache.values()).map(x => x.value));
|
||||
const allSymbols = flatten(allSymbolsSets);
|
||||
const allSymbols = allSymbolsSets.flat();
|
||||
return allSymbols.filter(symbolInformation => symbolInformation.name.toLowerCase().indexOf(query.toLowerCase()) !== -1);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import * as os from 'os';
|
||||
export class InMemoryDocument implements vscode.TextDocument {
|
||||
private readonly _lines: string[];
|
||||
|
||||
@ -13,7 +13,7 @@ export class InMemoryDocument implements vscode.TextDocument {
|
||||
private readonly _contents: string,
|
||||
public readonly version = 1,
|
||||
) {
|
||||
this._lines = this._contents.split(/\n/g);
|
||||
this._lines = this._contents.split(/\r\n|\n/g);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ export class InMemoryDocument implements vscode.TextDocument {
|
||||
languageId: string = '';
|
||||
isDirty: boolean = false;
|
||||
isClosed: boolean = false;
|
||||
eol: vscode.EndOfLine = vscode.EndOfLine.LF;
|
||||
eol: vscode.EndOfLine = os.platform() === 'win32' ? vscode.EndOfLine.CRLF : vscode.EndOfLine.LF;
|
||||
notebook: undefined;
|
||||
|
||||
get fileName(): string {
|
||||
@ -47,9 +47,9 @@ export class InMemoryDocument implements vscode.TextDocument {
|
||||
}
|
||||
positionAt(offset: number): vscode.Position {
|
||||
const before = this._contents.slice(0, offset);
|
||||
const newLines = before.match(/\n/g);
|
||||
const newLines = before.match(/\r\n|\n/g);
|
||||
const line = newLines ? newLines.length : 0;
|
||||
const preCharacters = before.match(/(\n|^).*$/g);
|
||||
const preCharacters = before.match(/(\r\n|\n|^).*$/g);
|
||||
return new vscode.Position(line, preCharacters ? preCharacters[0].length : 0);
|
||||
}
|
||||
getText(_range?: vscode.Range | undefined): string {
|
||||
|
@ -14,10 +14,10 @@ const CURSOR = '$$CURSOR$$';
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
suite.only('markdown.SmartSelect', () => {
|
||||
suite('markdown.SmartSelect', () => {
|
||||
test('Smart select single word', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(`Hel${CURSOR}lo`);
|
||||
assertNestedRangesEqual(ranges![0], [0, 1]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 0]);
|
||||
});
|
||||
test('Smart select multi-line paragraph', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -26,12 +26,12 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`For example, the[node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter]`,
|
||||
`(https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki).`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 2]);
|
||||
});
|
||||
test('Smart select paragraph', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(`Many of the core components and extensions to ${CURSOR}VS Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki).`);
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [0, 1]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 0]);
|
||||
});
|
||||
test('Smart select html block', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -40,7 +40,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`${CURSOR}<img alt="VS Code in action" src="https://user-images.githubusercontent.com/1487073/58344409-70473b80-7e0a-11e9-8570-b2efc6f8fa44.png">`,
|
||||
`</p>`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 2]);
|
||||
});
|
||||
test('Smart select header on header line', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -48,7 +48,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`# Header${CURSOR}`,
|
||||
`Hello`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [0, 1]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 1]);
|
||||
|
||||
});
|
||||
test('Smart select single word w grandparent header on text line', async () => {
|
||||
@ -59,7 +59,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`${CURSOR}Hello`
|
||||
));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [2, 2], [1, 2]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [2, 2], [1, 2]);
|
||||
});
|
||||
test('Smart select html block w parent header', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -69,7 +69,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`<img alt="VS Code in action" src="https://user-images.githubusercontent.com/1487073/58344409-70473b80-7e0a-11e9-8570-b2efc6f8fa44.png">`,
|
||||
`</p>`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [1, 3], [1, 3], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 3], [0, 3]);
|
||||
});
|
||||
test('Smart select fenced code block', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -78,7 +78,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`a${CURSOR}`,
|
||||
`~~~`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [0, 2]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 2]);
|
||||
});
|
||||
test('Smart select list', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -87,8 +87,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- ${CURSOR}item 2`,
|
||||
`- item 3`,
|
||||
`- item 4`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [1, 1], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [1, 1], [0, 3]);
|
||||
});
|
||||
test('Smart select list with fenced code block', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -100,7 +99,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- item 3`,
|
||||
`- item 4`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [1, 3], [0, 5]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [1, 3], [0, 5]);
|
||||
});
|
||||
test('Smart select multi cursor', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -112,8 +111,8 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- ${CURSOR}item 3`,
|
||||
`- item 4`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [0, 0], [0, 5]);
|
||||
assertNestedRangesEqual(ranges![1], [4, 4], [0, 5]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 0], [0, 5]);
|
||||
assertNestedLineNumbersEqual(ranges![1], [4, 4], [0, 5]);
|
||||
});
|
||||
test('Smart select nested block quotes', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -122,7 +121,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`> item 2`,
|
||||
`>> ${CURSOR}item 3`,
|
||||
`>> item 4`));
|
||||
assertNestedRangesEqual(ranges![0], [2, 4], [0, 4]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [0, 3]);
|
||||
});
|
||||
test('Smart select multi nested block quotes', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -131,8 +130,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`>> item 2`,
|
||||
`>>> ${CURSOR}item 3`,
|
||||
`>>>> item 4`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [2, 3], [2, 4], [1, 4], [0, 4]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [1, 3], [0, 3]);
|
||||
});
|
||||
test('Smart select subheader content', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -143,7 +141,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`${CURSOR}content 2`,
|
||||
`# main header 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [3, 3], [2, 3], [1, 3], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [3, 3], [2, 3], [1, 3], [0, 3]);
|
||||
});
|
||||
test('Smart select subheader line', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -154,7 +152,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`content 2`,
|
||||
`# main header 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [2, 3], [1, 3], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [2, 3], [1, 3], [0, 3]);
|
||||
});
|
||||
test('Smart select blank line', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -165,7 +163,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`content 2`,
|
||||
`# main header 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [1, 3], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [1, 3], [0, 3]);
|
||||
});
|
||||
test('Smart select line between paragraphs', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -174,7 +172,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`${CURSOR}`,
|
||||
`paragraph 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [0, 3]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 2]);
|
||||
});
|
||||
test('Smart select empty document', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(``, [new vscode.Position(0, 0)]);
|
||||
@ -196,7 +194,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`more content`,
|
||||
`# main header 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [4, 6], [3, 9], [3, 10], [2, 10], [1, 10], [0, 10]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [4, 6], [3, 9], [3, 10], [2, 10], [1, 10], [0, 10]);
|
||||
});
|
||||
test('Smart select list with one element without selecting child subheader', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -209,8 +207,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
``,
|
||||
`content 2`,
|
||||
`# main header 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [2, 3], [1, 3], [1, 6], [0, 6]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [1, 3], [1, 6], [0, 6]);
|
||||
});
|
||||
test('Smart select content under header then subheaders and their content', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -224,7 +221,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`content 2`,
|
||||
`# main header 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [0, 3], [0, 6]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [0, 3], [0, 6]);
|
||||
});
|
||||
test('Smart select last blockquote element under header then subheaders and their content', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -242,7 +239,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`content 2`,
|
||||
`# main header 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [4, 6], [2, 6], [1, 7], [1, 10], [0, 10]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [5, 5], [4, 5], [2, 5], [1, 7], [1, 10], [0, 10]);
|
||||
});
|
||||
test('Smart select content of subheader then subheader then content of main header then main header', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -266,7 +263,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- content 2`,
|
||||
`content 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [11, 12], [9, 12], [9, 17], [8, 17], [1, 17], [0, 17]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [11, 11], [9, 12], [9, 17], [8, 17], [1, 17], [0, 17]);
|
||||
});
|
||||
test('Smart select last line content of subheader then subheader then content of main header then main header', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -288,9 +285,9 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- content 2`,
|
||||
`- content 2`,
|
||||
`- content 2`,
|
||||
`${CURSOR}content 2`));
|
||||
`- ${CURSOR}content 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [16, 17], [14, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [17, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]);
|
||||
});
|
||||
test('Smart select last line content after content of subheader then subheader then content of main header then main header', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -312,9 +309,9 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- content 2`,
|
||||
`- content 2`,
|
||||
`- content 2`,
|
||||
`content 2${CURSOR}`));
|
||||
`- content 2${CURSOR}`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [16, 17], [14, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [17, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]);
|
||||
});
|
||||
test('Smart select fenced code block then list then rest of content', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -338,7 +335,7 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- content 2`,
|
||||
`- content 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [9, 11], [8, 12], [7, 17], [1, 17], [0, 17]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [9, 11], [8, 12], [8, 12], [7, 17], [1, 17], [0, 17]);
|
||||
});
|
||||
test('Smart select fenced code block then list then rest of content on fenced line', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
@ -362,15 +359,289 @@ suite.only('markdown.SmartSelect', () => {
|
||||
`- content 2`,
|
||||
`- content 2`));
|
||||
|
||||
assertNestedRangesEqual(ranges![0], [8, 12], [7, 17], [1, 17], [0, 17]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [8, 12], [7, 17], [1, 17], [0, 17]);
|
||||
});
|
||||
test('Smart select without multiple ranges', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`# main header 1`,
|
||||
``,
|
||||
``,
|
||||
`- ${CURSOR}paragraph`,
|
||||
`- content`));
|
||||
|
||||
assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [1, 4], [0, 4]);
|
||||
});
|
||||
test('Smart select on second level of a list', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`* level 0`,
|
||||
` * level 1`,
|
||||
` * level 1`,
|
||||
` * level 2`,
|
||||
` * level 1`,
|
||||
` * level ${CURSOR}1`,
|
||||
`* level 0`));
|
||||
|
||||
assertNestedLineNumbersEqual(ranges![0], [5, 5], [1, 5], [0, 5], [0, 6]);
|
||||
});
|
||||
test('Smart select on third level of a list', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`* level 0`,
|
||||
` * level 1`,
|
||||
` * level 1`,
|
||||
` * level ${CURSOR}2`,
|
||||
` * level 2`,
|
||||
` * level 1`,
|
||||
` * level 1`,
|
||||
`* level 0`));
|
||||
assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [2, 4], [1, 6], [0, 6], [0, 7]);
|
||||
});
|
||||
test('Smart select level 2 then level 1', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`* level 1`,
|
||||
` * level ${CURSOR}2`,
|
||||
` * level 2`,
|
||||
`* level 1`));
|
||||
assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 2], [0, 2], [0, 3]);
|
||||
});
|
||||
test('Smart select last list item', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`- level 1`,
|
||||
`- level 2`,
|
||||
`- level 2`,
|
||||
`- level ${CURSOR}1`));
|
||||
assertNestedLineNumbersEqual(ranges![0], [3, 3], [0, 3]);
|
||||
});
|
||||
test('Smart select without multiple ranges', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`# main header 1`,
|
||||
``,
|
||||
``,
|
||||
`- ${CURSOR}paragraph`,
|
||||
`- content`));
|
||||
|
||||
assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [1, 4], [0, 4]);
|
||||
});
|
||||
test('Smart select on second level of a list', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`* level 0`,
|
||||
` * level 1`,
|
||||
` * level 1`,
|
||||
` * level 2`,
|
||||
` * level 1`,
|
||||
` * level ${CURSOR}1`,
|
||||
`* level 0`));
|
||||
|
||||
assertNestedLineNumbersEqual(ranges![0], [5, 5], [1, 5], [0, 5], [0, 6]);
|
||||
});
|
||||
test('Smart select on third level of a list', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`* level 0`,
|
||||
` * level 1`,
|
||||
` * level 1`,
|
||||
` * level ${CURSOR}2`,
|
||||
` * level 2`,
|
||||
` * level 1`,
|
||||
` * level 1`,
|
||||
`* level 0`));
|
||||
assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [2, 4], [1, 6], [0, 6], [0, 7]);
|
||||
});
|
||||
test('Smart select level 2 then level 1', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`* level 1`,
|
||||
` * level ${CURSOR}2`,
|
||||
` * level 2`,
|
||||
`* level 1`));
|
||||
assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 2], [0, 2], [0, 3]);
|
||||
});
|
||||
test('Smart select bold', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`stuff here **new${CURSOR}item** and here`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 13, 0, 30], [0, 11, 0, 32], [0, 0, 0, 41]);
|
||||
});
|
||||
test('Smart select link', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`stuff here [text](https${CURSOR}://google.com) and here`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 18, 0, 46], [0, 17, 0, 47], [0, 11, 0, 47], [0, 0, 0, 56]);
|
||||
});
|
||||
test('Smart select brackets', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`stuff here [te${CURSOR}xt](https://google.com) and here`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 12, 0, 26], [0, 11, 0, 27], [0, 11, 0, 47], [0, 0, 0, 56]);
|
||||
});
|
||||
test('Smart select brackets under header in list', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`# main header 1`,
|
||||
``,
|
||||
`- list`,
|
||||
`paragraph`,
|
||||
`## sub header`,
|
||||
`- list`,
|
||||
`- stuff here [te${CURSOR}xt](https://google.com) and here`,
|
||||
`- list`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [6, 14, 6, 28], [6, 13, 6, 29], [6, 13, 6, 49], [6, 0, 6, 58], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]);
|
||||
});
|
||||
test('Smart select link under header in list', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`# main header 1`,
|
||||
``,
|
||||
`- list`,
|
||||
`paragraph`,
|
||||
`## sub header`,
|
||||
`- list`,
|
||||
`- stuff here [text](${CURSOR}https://google.com) and here`,
|
||||
`- list`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [6, 20, 6, 48], [6, 19, 6, 49], [6, 13, 6, 49], [6, 0, 6, 58], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]);
|
||||
});
|
||||
test('Smart select bold within list where multiple bold elements exists', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`# main header 1`,
|
||||
``,
|
||||
`- list`,
|
||||
`paragraph`,
|
||||
`## sub header`,
|
||||
`- list`,
|
||||
`- stuff here [text] **${CURSOR}items in here** and **here**`,
|
||||
`- list`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [6, 22, 6, 45], [6, 20, 6, 47], [6, 0, 6, 60], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]);
|
||||
});
|
||||
test('Smart select link in paragraph with multiple links', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`This[extension](https://marketplace.visualstudio.com/items?itemName=meganrogge.template-string-converter) addresses this [requ${CURSOR}est](https://github.com/microsoft/vscode/issues/56704) to convert Javascript/Typescript quotes to backticks when has been entered within a string.`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 123, 0, 140], [0, 122, 0, 141], [0, 122, 0, 191], [0, 0, 0, 283]);
|
||||
});
|
||||
test('Smart select bold link', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`**[extens${CURSOR}ion](https://google.com)**`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 3, 0, 22], [0, 2, 0, 23], [0, 2, 0, 43], [0, 2, 0, 43], [0, 0, 0, 45], [0, 0, 0, 45]);
|
||||
});
|
||||
test('Smart select inline code block', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`[\`code ${CURSOR} link\`]`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 2, 0, 22], [0, 1, 0, 23], [0, 0, 0, 24]);
|
||||
});
|
||||
test('Smart select link with inline code block text', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`[\`code ${CURSOR} link\`](http://example.com)`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 2, 0, 22], [0, 1, 0, 23], [0, 1, 0, 23], [0, 0, 0, 24], [0, 0, 0, 44], [0, 0, 0, 44]);
|
||||
});
|
||||
test('Smart select italic', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`*some nice ${CURSOR}text*`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 1, 0, 25], [0, 0, 0, 26], [0, 0, 0, 26]);
|
||||
});
|
||||
test('Smart select italic link', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`*[extens${CURSOR}ion](https://google.com)*`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 2, 0, 21], [0, 1, 0, 22], [0, 1, 0, 42], [0, 1, 0, 42], [0, 0, 0, 43], [0, 0, 0, 43]);
|
||||
});
|
||||
test('Smart select italic on end', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`*word1 word2 word3${CURSOR}*`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 1, 0, 28], [0, 0, 0, 29], [0, 0, 0, 29]);
|
||||
});
|
||||
test('Smart select italic then bold', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`outer text **bold words *italic ${CURSOR} words* bold words** outer text`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 25, 0, 48], [0, 24, 0, 49], [0, 13, 0, 60], [0, 11, 0, 62], [0, 0, 0, 73]);
|
||||
});
|
||||
test('Smart select bold then italic', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`outer text *italic words **bold ${CURSOR} words** italic words* outer text`
|
||||
));
|
||||
assertNestedRangesEqual(ranges![0], [0, 27, 0, 48], [0, 25, 0, 50], [0, 12, 0, 63], [0, 11, 0, 64], [0, 0, 0, 75]);
|
||||
});
|
||||
test('Third level header from release notes', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`---`,
|
||||
`Order: 60`,
|
||||
`TOCTitle: October 2020`,
|
||||
`PageTitle: Visual Studio Code October 2020`,
|
||||
`MetaDescription: Learn what is new in the Visual Studio Code October 2020 Release (1.51)`,
|
||||
`MetaSocialImage: 1_51/release-highlights.png`,
|
||||
`Date: 2020-11-6`,
|
||||
`DownloadVersion: 1.51.1`,
|
||||
`---`,
|
||||
`# October 2020 (version 1.51)`,
|
||||
``,
|
||||
`**Update 1.51.1**: The update addresses these [issues](https://github.com/microsoft/vscode/issues?q=is%3Aissue+milestone%3A%22October+2020+Recovery%22+is%3Aclosed+).`,
|
||||
``,
|
||||
`<!-- DOWNLOAD_LINKS_PLACEHOLDER -->`,
|
||||
``,
|
||||
`---`,
|
||||
``,
|
||||
`Welcome to the October 2020 release of Visual Studio Code. As announced in the [October iteration plan](https://github.com/microsoft/vscode/issues/108473), we focused on housekeeping GitHub issues and pull requests as documented in our issue grooming guide.`,
|
||||
``,
|
||||
`We also worked with our partners at GitHub on GitHub Codespaces, which ended up being more involved than originally anticipated. To that end, we'll continue working on housekeeping for part of the November iteration.`,
|
||||
``,
|
||||
`During this housekeeping milestone, we also addressed several feature requests and community [pull requests](#thank-you). Read on to learn about new features and settings.`,
|
||||
``,
|
||||
`## Workbench`,
|
||||
``,
|
||||
`### More prominent pinned tabs`,
|
||||
``,
|
||||
`${CURSOR}Pinned tabs will now always show their pin icon, even while inactive, to make them easier to identify. If an editor is both pinned and contains unsaved changes, the icon reflects both states.`,
|
||||
``,
|
||||
``
|
||||
)
|
||||
);
|
||||
assertNestedRangesEqual(ranges![0], [27, 0, 27, 201], [26, 0, 29, 70], [25, 0, 29, 70], [24, 0, 29, 70], [23, 0, 29, 70], [10, 0, 29, 70], [9, 0, 29, 70]);
|
||||
});
|
||||
});
|
||||
|
||||
function assertNestedRangesEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number][]) {
|
||||
function assertNestedLineNumbersEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number][]) {
|
||||
const lineage = getLineage(range);
|
||||
assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length}`);
|
||||
assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length} ${getValues(lineage)}`);
|
||||
for (let i = 0; i < lineage.length; i++) {
|
||||
assertRangesEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][1], `parent at a depth of ${i}`);
|
||||
assertLineNumbersEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][1], `parent at a depth of ${i}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertNestedRangesEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number, number, number][]) {
|
||||
const lineage = getLineage(range);
|
||||
assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length} ${getValues(lineage)}`);
|
||||
for (let i = 0; i < lineage.length; i++) {
|
||||
assertLineNumbersEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][2], `parent at a depth of ${i}`);
|
||||
assert(lineage[i].range.start.character === expectedRanges[i][1], `parent at a depth of ${i} on start char`);
|
||||
assert(lineage[i].range.end.character === expectedRanges[i][3], `parent at a depth of ${i} on end char`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,7 +655,13 @@ function getLineage(range: vscode.SelectionRange): vscode.SelectionRange[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
function assertRangesEqual(selectionRange: vscode.SelectionRange, startLine: number, endLine: number, message: string) {
|
||||
function getValues(ranges: vscode.SelectionRange[]): string[] {
|
||||
return ranges.map(range => {
|
||||
return range.range.start.line + ' ' + range.range.start.character + ' ' + range.range.end.line + ' ' + range.range.end.character;
|
||||
});
|
||||
}
|
||||
|
||||
function assertLineNumbersEqual(selectionRange: vscode.SelectionRange, startLine: number, endLine: number, message: string) {
|
||||
assert.strictEqual(selectionRange.range.start.line, startLine, `failed on start line ${message}`);
|
||||
assert.strictEqual(selectionRange.range.end.line, endLine, `failed on end line ${message}`);
|
||||
}
|
||||
|
@ -15,8 +15,4 @@ export function equals<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, itemEq
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function flatten<T>(arr: ReadonlyArray<T>[]): T[] {
|
||||
return ([] as T[]).concat.apply([], arr);
|
||||
}
|
@ -1,4 +1,10 @@
|
||||
[b](b)
|
||||
[b](b.md)
|
||||
[b](./b.md)
|
||||
[b](/b.md)
|
||||
|
||||
[b.md](b.md)
|
||||
|
||||
[./b.md](./b.md)
|
||||
|
||||
[/b.md](/b.md)
|
||||
|
||||
[b#header1](b#header1)
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
# b
|
||||
|
||||
[](./a)
|
||||
[./a](./a)
|
||||
|
||||
# header1
|
@ -6,6 +6,8 @@
|
||||
"lib": [
|
||||
"es6",
|
||||
"es2015.promise",
|
||||
"es2019.array",
|
||||
"es2020.string",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
|
@ -2131,10 +2131,10 @@ he@1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
|
||||
|
||||
highlight.js@9.15.10:
|
||||
version "9.15.10"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2"
|
||||
integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==
|
||||
highlight.js@10.1.2:
|
||||
version "10.1.2"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.1.2.tgz#c20db951ba1c22c055010648dfffd7b2a968e00c"
|
||||
integrity sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA==
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user