Merge VS Code 1.21 source code (#1067)

* Initial VS Code 1.21 file copy with patches

* A few more merges

* Post npm install

* Fix batch of build breaks

* Fix more build breaks

* Fix more build errors

* Fix more build breaks

* Runtime fixes 1

* Get connection dialog working with some todos

* Fix a few packaging issues

* Copy several node_modules to package build to fix loader issues

* Fix breaks from master

* A few more fixes

* Make tests pass

* First pass of license header updates

* Second pass of license header updates

* Fix restore dialog issues

* Remove add additional themes menu items

* fix select box issues where the list doesn't show up

* formatting

* Fix editor dispose issue

* Copy over node modules to correct location on all platforms
This commit is contained in:
Karl Burtram
2018-04-04 15:27:51 -07:00
committed by GitHub
parent 5fba3e31b4
commit dafb780987
9412 changed files with 141255 additions and 98813 deletions

View File

@@ -1,4 +1,5 @@
src/**
test/**
out/test/**
tsconfig.json
tsconfig.json
build/**

View File

@@ -1,29 +1,52 @@
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
[{
"name": "textmate/git.tmbundle",
"version": "0.0.0",
"license": "MIT",
"repositoryURL": "https://github.com/textmate/git.tmbundle",
"licenseDetail": [
"Copyright (c) 2008 Tim Harper",
"",
"Permission is hereby granted, free of charge, to any person obtaining",
"a copy of this software and associated documentation files (the\"",
"Software\"), to deal in the Software without restriction, including",
"without limitation the rights to use, copy, modify, merge, publish,",
"distribute, sublicense, and/or sell copies of the Software, and to",
"permit persons to whom the Software is furnished to do so, subject to",
"the following conditions:",
"",
"The above copyright notice and this permission notice shall be",
"included in all copies or substantial portions of the Software.",
"",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,",
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF",
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND",
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE",
"LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION",
"OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION",
"WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
]
}]
[
{
"name": "textmate/git.tmbundle",
"version": "0.0.0",
"license": "MIT",
"repositoryURL": "https://github.com/textmate/git.tmbundle",
"licenseDetail": [
"Copyright (c) 2008 Tim Harper",
"",
"Permission is hereby granted, free of charge, to any person obtaining",
"a copy of this software and associated documentation files (the\"",
"Software\"), to deal in the Software without restriction, including",
"without limitation the rights to use, copy, modify, merge, publish,",
"distribute, sublicense, and/or sell copies of the Software, and to",
"permit persons to whom the Software is furnished to do so, subject to",
"the following conditions:",
"",
"The above copyright notice and this permission notice shall be",
"included in all copies or substantial portions of the Software.",
"",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,",
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF",
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND",
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE",
"LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION",
"OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION",
"WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
]
},
{
"name": "textmate/diff.tmbundle",
"version": "0.0.0",
"license": "TextMate Bundle License",
"repositoryURL": "https://github.com/textmate/diff.tmbundle",
"licenseDetail": [
"Copyright (c) textmate-diff.tmbundle project authors",
"",
"If not otherwise specified (see below), files in this repository fall under the following license:",
"",
"Permission to copy, use, modify, sell and distribute this",
"software is granted. This software is provided \"as is\" without",
"express or implied warranty, and with no claim as to its",
"suitability for any purpose.",
"",
"An exception is made for files in readable text which contain their own license information,",
"or files where an accompanying file exists (in the same directory) with a \"-license\" suffix added",
"to the base-name name of the original file, and an extension of txt, html, or similar. For example",
"\"tidy\" is accompanied by \"tidy-license.txt\"."
]
}
]

2
extensions/git/README.md Normal file
View File

@@ -0,0 +1,2 @@
# Git integration for Visual Studio Code

View File

@@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
var updateGrammar = require('../../../build/npm/update-grammar');
updateGrammar.update('textmate/git.tmbundle', 'Syntaxes/Git%20Commit%20Message.tmLanguage', './syntaxes/git-commit.tmLanguage.json');
updateGrammar.update('textmate/git.tmbundle', 'Syntaxes/Git%20Rebase%20Message.tmLanguage', './syntaxes/git-rebase.tmLanguage.json');
updateGrammar.update('textmate/diff.tmbundle', 'Syntaxes/Diff.plist', './syntaxes/diff.tmLanguage.json');

View File

@@ -0,0 +1,11 @@
{
"comments": {
"lineComment": "#",
"blockComment": [ "#", " " ]
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
]
}

View File

@@ -0,0 +1,11 @@
{
"comments": {
"lineComment": "#",
"blockComment": [ "#", " " ]
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
]
}

View File

@@ -0,0 +1,11 @@
{
"comments": {
"lineComment": "#",
"blockComment": [ "#", " " ]
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
]
}

View File

@@ -1,36 +0,0 @@
{
"name": "git",
"version": "0.0.1",
"dependencies": {
"applicationinsights": {
"version": "0.18.0",
"from": "applicationinsights@0.18.0",
"resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz"
},
"byline": {
"version": "5.0.0",
"from": "byline@latest",
"resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz"
},
"iconv-lite": {
"version": "0.4.15",
"from": "iconv-lite@0.4.15",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz"
},
"vscode-extension-telemetry": {
"version": "0.0.8",
"from": "vscode-extension-telemetry@>=0.0.8 <0.0.9",
"resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz"
},
"vscode-nls": {
"version": "2.0.2",
"from": "vscode-nls@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
},
"winreg": {
"version": "1.2.3",
"from": "winreg@1.2.3",
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.3.tgz"
}
}
}

View File

@@ -1,9 +1,9 @@
{
"name": "git",
"displayName": "%displayName%",
"description": "%description%",
"publisher": "vscode",
"displayName": "git",
"description": "Git",
"version": "0.0.1",
"version": "1.0.0",
"engines": {
"vscode": "^1.5.0"
},
@@ -16,9 +16,11 @@
"*"
],
"main": "./out/main",
"icon": "resources/icons/git.png",
"scripts": {
"compile": "gulp compile-extension:git",
"watch": "gulp watch-extension:git"
"watch": "gulp watch-extension:git",
"update-grammar": "node ./build/update-grammars.js"
},
"contributes": {
"commands": [
@@ -68,6 +70,15 @@
"dark": "resources/icons/dark/open-file.svg"
}
},
{
"command": "git.openFile2",
"title": "%command.openFile%",
"category": "Git",
"icon": {
"light": "resources/icons/light/open-file-mono.svg",
"dark": "resources/icons/dark/open-file-mono.svg"
}
},
{
"command": "git.openHEADFile",
"title": "%command.openHEADFile%",
@@ -327,35 +338,35 @@
},
{
"command": "git.close",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.refresh",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.openFile",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.openHEADFile",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.openChange",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stage",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stageAll",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stageSelectedRanges",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stageChange",
@@ -363,155 +374,159 @@
},
{
"command": "git.revertSelectedRanges",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.revertChange",
"when": "false"
},
{
"command": "git.openFile2",
"when": "false"
},
{
"command": "git.unstage",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.unstageAll",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.unstageSelectedRanges",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.clean",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && !gitFreshRepository"
},
{
"command": "git.cleanAll",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && !gitFreshRepository"
},
{
"command": "git.commit",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.commitStaged",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.commitStagedSigned",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.commitStagedAmend",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.commitAll",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.commitAllSigned",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.commitAllAmend",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.undoCommit",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.checkout",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.branch",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.deleteBranch",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.renameBranch",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pull",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pullFrom",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pullRebase",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pullFrom",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.merge",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.createTag",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.fetch",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.push",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pushTo",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pushWithTags",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.sync",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.syncRebase",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.publish",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.showOutput",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled"
},
{
"command": "git.ignore",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stashIncludeUntracked",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stash",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stashPop",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.stashPopLatest",
"when": "gitOpenRepositoryCount != 0"
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
}
],
"scm/title": [
@@ -618,7 +633,7 @@
{
"command": "git.cleanAll",
"group": "4_stage",
"when": "scmProvider == git"
"when": "scmProvider == git && !gitFreshRepository"
},
{
"command": "git.stashIncludeUntracked",
@@ -676,7 +691,7 @@
},
{
"command": "git.cleanAll",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmResourceGroup == workingTree && !gitFreshRepository",
"group": "1_modification"
},
{
@@ -686,7 +701,7 @@
},
{
"command": "git.cleanAll",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmResourceGroup == workingTree && !gitFreshRepository",
"group": "inline"
},
{
@@ -701,11 +716,21 @@
"when": "scmProvider == git && scmResourceGroup == merge",
"group": "1_modification"
},
{
"command": "git.openFile",
"when": "scmProvider == git && scmResourceGroup == merge",
"group": "navigation"
},
{
"command": "git.stage",
"when": "scmProvider == git && scmResourceGroup == merge",
"group": "inline"
},
{
"command": "git.openFile2",
"when": "scmProvider == git && scmResourceGroup == merge && config.git.showInlineOpenFileAction",
"group": "inline0"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmResourceGroup == index",
@@ -731,6 +756,11 @@
"when": "scmProvider == git && scmResourceGroup == index",
"group": "inline"
},
{
"command": "git.openFile2",
"when": "scmProvider == git && scmResourceGroup == index && config.git.showInlineOpenFileAction",
"group": "inline0"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmResourceGroup == workingTree",
@@ -753,12 +783,12 @@
},
{
"command": "git.clean",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmResourceGroup == workingTree && !gitFreshRepository",
"group": "1_modification"
},
{
"command": "git.clean",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmResourceGroup == workingTree && !gitFreshRepository",
"group": "inline"
},
{
@@ -766,6 +796,11 @@
"when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "inline"
},
{
"command": "git.openFile2",
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.showInlineOpenFileAction",
"group": "inline0"
},
{
"command": "git.ignore",
"when": "scmProvider == git && scmResourceGroup == workingTree",
@@ -776,27 +811,27 @@
{
"command": "git.openFile",
"group": "navigation",
"when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != extension && resourceScheme != merge-conflict.conflict-diff"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
},
{
"command": "git.openChange",
"group": "navigation",
"when": "gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme == file"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme == file"
},
{
"command": "git.stageSelectedRanges",
"group": "2_git@1",
"when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
},
{
"command": "git.unstageSelectedRanges",
"group": "2_git@2",
"when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
},
{
"command": "git.revertSelectedRanges",
"group": "2_git@3",
"when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
}
],
"scm/change/title": [
@@ -828,6 +863,11 @@
"default": null,
"isExecutable": true
},
"git.autoRepositoryDetection": {
"type": "boolean",
"description": "%config.autoRepositoryDetection%",
"default": true
},
"git.autorefresh": {
"type": "boolean",
"description": "%config.autorefresh%",
@@ -898,6 +938,32 @@
"type": "boolean",
"default": true,
"description": "%config.decorations.enabled%"
},
"git.promptToSaveFilesBeforeCommit": {
"type": "boolean",
"default": false,
"description": "%config.promptToSaveFilesBeforeCommit%"
},
"git.showInlineOpenFileAction": {
"type": "boolean",
"default": true,
"description": "%config.showInlineOpenFileAction%"
},
"git.inputValidation": {
"type": "string",
"enum": [
"always",
"warn",
"off"
],
"default": "warn",
"description": "%config.inputValidation%"
},
"git.detectSubmodules": {
"type": "boolean",
"scope": "resource",
"default": true,
"description": "%config.detectSubmodules%"
}
}
},
@@ -946,15 +1012,86 @@
"dark": "#6c6cc4",
"highContrast": "#6c6cc4"
}
},
{
"id": "gitDecoration.submoduleResourceForeground",
"description": "%colors.submodule%",
"defaults": {
"light": "#1258a7",
"dark": "#8db9e2",
"highContrast": "#8db9e2"
}
}
]
],
"languages": [
{
"id": "git-commit",
"aliases": [
"Git Commit Message",
"git-commit"
],
"filenames": [
"COMMIT_EDITMSG",
"MERGE_MSG"
],
"configuration": "./languages/git-commit.language-configuration.json"
},
{
"id": "git-rebase",
"aliases": [
"Git Rebase Message",
"git-rebase"
],
"filenames": [
"git-rebase-todo"
],
"configuration": "./languages/git-rebase.language-configuration.json"
},
{
"id": "diff",
"aliases": [
"Diff",
"diff"
],
"extensions": [
".patch",
".diff",
".rej"
],
"configuration": "./languages/diff.language-configuration.json"
}
],
"grammars": [
{
"language": "git-commit",
"scopeName": "text.git-commit",
"path": "./syntaxes/git-commit.tmLanguage.json"
},
{
"language": "git-rebase",
"scopeName": "text.git-rebase",
"path": "./syntaxes/git-rebase.tmLanguage.json"
},
{
"language": "diff",
"scopeName": "source.diff",
"path": "./syntaxes/diff.tmLanguage.json"
}
],
"configurationDefaults": {
"[git-commit]": {
"editor.rulers": [
72
]
}
}
},
"dependencies": {
"byline": "^5.0.0",
"file-type": "^7.2.0",
"iconv-lite": "0.4.19",
"vscode-extension-telemetry": "0.0.8",
"vscode-nls": "2.0.2",
"vscode-extension-telemetry": "0.0.15",
"vscode-nls": "^3.2.1",
"which": "^1.3.0"
},
"devDependencies": {
@@ -965,4 +1102,4 @@
"@types/which": "^1.0.28",
"mocha": "^3.2.0"
}
}
}

View File

@@ -1,4 +1,6 @@
{
"displayName": "Git",
"description": "Git SCM Integration",
"command.clone": "Clone",
"command.init": "Initialize Repository",
"command.close": "Close Repository",
@@ -49,12 +51,13 @@
"command.stashPopLatest": "Pop Latest Stash",
"config.enabled": "Whether git is enabled",
"config.path": "Path to the git executable",
"config.autoRepositoryDetection": "Whether repositories should be automatically detected",
"config.autorefresh": "Whether auto refreshing is enabled",
"config.autofetch": "Whether auto fetching is enabled",
"config.enableLongCommitWarning": "Whether long commit messages should be warned about",
"config.confirmSync": "Confirm before synchronizing git repositories",
"config.countBadge": "Controls the git badge counter. `all` counts all changes. `tracked` counts only the tracked changes. `off` turns it off.",
"config.checkoutType": "Controls what type of branches are listed when running `Checkout to...`. `all` shows all refs, `local` shows only the local branchs, `tags` shows only tags and `remote` shows only remote branches.",
"config.checkoutType": "Controls what type of branches are listed when running `Checkout to...`. `all` shows all refs, `local` shows only the local branches, `tags` shows only tags and `remote` shows only remote branches.",
"config.ignoreLegacyWarning": "Ignores the legacy Git warning",
"config.ignoreMissingGitWarning": "Ignores the warning when Git is missing",
"config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository",
@@ -63,9 +66,14 @@
"config.enableCommitSigning": "Enables commit signing with GPG.",
"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 if Git contributes colors and badges to the explorer and the open editors view.",
"config.promptToSaveFilesBeforeCommit": "Controls whether Git should check for unsaved files before committing.",
"config.showInlineOpenFileAction": "Controls whether to show an inline Open File action in the Git changes view.",
"config.inputValidation": "Controls when to show commit message input validation.",
"config.detectSubmodules": "Controls whether to automatically detect git submodules.",
"colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.",
"colors.untracked": "Color for untracked resources.",
"colors.ignored": "Color for ignored resources.",
"colors.conflict": "Color for resources with conflicts."
"colors.conflict": "Color for resources with conflicts.",
"colors.submodule": "Color for submodule resources."
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon fill="#C5C5C5" points="10,2 7.414,2 8.414,3 9,3 9,3.586 9,4 9,4.414 9,6 12,6 12,13 4,13 4,8 3,8 3,14 13,14 13,5"/><polygon fill="#C5C5C5" points="5,1 3,1 5,3 1,3 1,5 5,5 3,7 5,7 8,4"/></svg>

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon fill="#424242" points="10,2 7.414,2 8.414,3 9,3 9,3.586 9,4 9,4.414 9,6 12,6 12,13 4,13 4,8 3,8 3,14 13,14 13,5"/><polygon fill="#424242" points="5,1 3,1 5,3 1,3 1,5 5,5 3,7 5,7 8,4"/></svg>

After

Width:  |  Height:  |  Size: 262 B

View File

@@ -1,3 +1 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon fill="#656565" points="10,2 7.414,2 8.414,3 9,3 9,3.586 9,4 9,4.414 9,6 12,6 12,13 4,13 4,8 3,8 3,14 13,14 13,5"/><polygon fill="#00539C" points="5,1 3,1 5,3 1,3 1,5 5,5 3,7 5,7 8,4"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon fill="#656565" points="10,2 7.414,2 8.414,3 9,3 9,3.586 9,4 9,4.414 9,6 12,6 12,13 4,13 4,8 3,8 3,14 13,14 13,5"/><polygon fill="#00539C" points="5,1 3,1 5,3 1,3 1,5 5,5 3,7 5,7 8,4"/></svg>

Before

Width:  |  Height:  |  Size: 417 B

After

Width:  |  Height:  |  Size: 262 B

View File

@@ -6,7 +6,7 @@
'use strict';
import { Model } from './model';
import { SourceControlInputBox, Uri } from 'vscode';
import { Uri } from 'vscode';
export interface InputBox {
value: string;

View File

@@ -5,7 +5,7 @@
'use strict';
import { workspace, Disposable, EventEmitter, Memento, window, MessageItem, ConfigurationTarget, commands, Uri } from 'vscode';
import { workspace, Disposable, EventEmitter, Memento, window, MessageItem, ConfigurationTarget } from 'vscode';
import { GitErrorCodes } from './git';
import { Repository, Operation } from './repository';
import { eventToPromise, filterEvent, onceEvent } from './util';
@@ -54,20 +54,14 @@ export class AutoFetcher {
}
const yes: MessageItem = { title: localize('yes', "Yes") };
const readMore: MessageItem = { title: localize('read more', "Read More") };
const no: MessageItem = { isCloseAffordance: true, title: localize('no', "No") };
const askLater: MessageItem = { title: localize('not now', "Ask Me Later") };
const result = await window.showInformationMessage(localize('suggest auto fetch', "Would you like Code to periodically run `git fetch`?"), yes, readMore, no, askLater);
const result = await window.showInformationMessage(localize('suggest auto fetch', "Would you like Code to [periodically run 'git fetch']({0})?", 'https://go.microsoft.com/fwlink/?linkid=865294'), yes, no, askLater);
if (result === askLater) {
return;
}
if (result === readMore) {
commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=865294'));
return this.onFirstGoodRemoteOperation();
}
if (result === yes) {
const gitConfig = workspace.getConfiguration('git');
gitConfig.update('autofetch', true, ConfigurationTarget.Global);

View File

@@ -10,9 +10,10 @@ import { Ref, RefType, Git, GitErrorCodes, Branch } from './git';
import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository';
import { Model } from './model';
import { toGitUri, fromGitUri } from './uri';
import { grep } from './util';
import { applyLineChanges, intersectDiffWithRange, toLineRanges, invertLineChange } from './staging';
import { grep, isDescendant } from './util';
import { applyLineChanges, intersectDiffWithRange, toLineRanges, invertLineChange, getModifiedRange } from './staging';
import * as path from 'path';
import { lstat, Stats } from 'fs';
import * as os from 'os';
import TelemetryReporter from 'vscode-extension-telemetry';
import * as nls from 'vscode-nls';
@@ -168,8 +169,28 @@ export class CommandCenter {
}
private async _openResource(resource: Resource, preview?: boolean, preserveFocus?: boolean, preserveSelection?: boolean): Promise<void> {
const left = await this.getLeftResource(resource);
const right = await this.getRightResource(resource);
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 {
left = await this.getLeftResource(resource);
right = await this.getRightResource(resource);
}
const title = this.getTitle(resource);
if (!right) {
@@ -216,7 +237,7 @@ export class CommandCenter {
}
const { size, object } = await repository.lstree(gitRef, uri.fsPath);
const { mimetype, encoding } = await repository.detectObjectType(object);
const { mimetype } = await repository.detectObjectType(object);
if (mimetype === 'text/plain') {
return toGitUri(uri, ref);
@@ -330,7 +351,6 @@ export class CommandCenter {
const config = workspace.getConfiguration('git');
let value = config.get<string>('defaultCloneDirectory') || os.homedir();
value = value.replace(/^~/, os.homedir());
const parentPath = await window.showInputBox({
prompt: localize('parent', "Parent Directory"),
@@ -358,11 +378,10 @@ export class CommandCenter {
statusBarItem.command = cancelCommandId;
statusBarItem.show();
const clonePromise = this.git.clone(url, parentPath, tokenSource.token);
const clonePromise = this.git.clone(url, parentPath.replace(/^~/, os.homedir()), tokenSource.token);
try {
window.withProgress({ location: ProgressLocation.SourceControl, title: localize('cloning', "Cloning git repository...") }, () => clonePromise);
// window.withProgress({ location: ProgressLocation.Window, title: localize('cloning', "Cloning git repository...") }, () => clonePromise);
const repositoryPath = await clonePromise;
@@ -484,7 +503,10 @@ export class CommandCenter {
}
if (resource) {
uris = [...resourceStates.map(r => r.resourceUri), resource.resourceUri];
const resources = ([resource, ...resourceStates] as Resource[])
.filter(r => r.type !== Status.DELETED && r.type !== Status.INDEX_DELETED);
uris = resources.map(r => r.resourceUri);
}
}
@@ -511,6 +533,11 @@ export class CommandCenter {
}
}
@command('git.openFile2')
async openFile2(arg?: Resource | Uri, ...resourceStates: SourceControlResourceState[]): Promise<void> {
this.openFile(arg, ...resourceStates);
}
@command('git.openHEADFile')
async openHEADFile(arg?: Resource | Uri): Promise<void> {
let resource: Resource | undefined = undefined;
@@ -709,10 +736,7 @@ export class CommandCenter {
const modifiedDocument = textEditor.document;
const selections = textEditor.selections;
const selectedChanges = changes.filter(change => {
const modifiedRange = change.modifiedEndLineNumber === 0
? new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(change.modifiedStartLineNumber).range.start)
: new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(change.modifiedEndLineNumber - 1).range.end);
const modifiedRange = getModifiedRange(modifiedDocument, change);
return selections.every(selection => !selection.intersection(modifiedRange));
});
@@ -940,6 +964,29 @@ export class CommandCenter {
opts?: CommitOptions
): Promise<boolean> {
const config = workspace.getConfiguration('git');
const promptToSaveFilesBeforeCommit = config.get<boolean>('promptToSaveFilesBeforeCommit') === true;
if (promptToSaveFilesBeforeCommit) {
const unsavedTextDocuments = workspace.textDocuments
.filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath));
if (unsavedTextDocuments.length > 0) {
const message = unsavedTextDocuments.length === 1
? localize('unsaved files single', "The following file is unsaved: {0}.\n\nWould you like to save it before comitting?", path.basename(unsavedTextDocuments[0].uri.fsPath))
: localize('unsaved files', "There are {0} unsaved files.\n\nWould you like to save them before comitting?", unsavedTextDocuments.length);
const saveAndCommit = localize('save and commit', "Save All & Commit");
const commit = localize('commit', "Commit Anyway");
const pick = await window.showWarningMessage(message, { modal: true }, saveAndCommit, commit);
if (pick === saveAndCommit) {
await Promise.all(unsavedTextDocuments.map(d => d.save()));
await repository.status();
} else if (pick !== commit) {
return false; // do not commit on cancel
}
}
}
const enableSmartCommit = config.get<boolean>('enableSmartCommit') === true;
const enableCommitSigning = config.get<boolean>('enableCommitSigning') === true;
const noStagedChanges = repository.indexGroup.resourceStates.length === 0;
@@ -963,6 +1010,8 @@ export class CommandCenter {
if (!opts) {
opts = { all: noStagedChanges };
} else if (!opts.all && noStagedChanges) {
opts = { ...opts, all: true };
}
// enable signing of commits if configurated
@@ -996,8 +1045,14 @@ export class CommandCenter {
return message;
}
let value: string | undefined = undefined;
if (opts && opts.amend && repository.HEAD && repository.HEAD.commit) {
value = (await repository.getCommit(repository.HEAD.commit)).message;
}
return await window.showInputBox({
value: opts && opts.defaultMsg,
value,
placeHolder: localize('commit message', "Commit message"),
prompt: localize('provide commit message', "Please provide a commit message"),
ignoreFocusOut: true
@@ -1041,15 +1096,7 @@ export class CommandCenter {
@command('git.commitStagedAmend', { repository: true })
async commitStagedAmend(repository: Repository): Promise<void> {
let msg;
if (repository.HEAD) {
if (repository.HEAD.commit) {
let id = repository.HEAD.commit;
let commit = await repository.getCommit(id);
msg = commit.message;
}
}
await this.commitWithAnyInput(repository, { all: false, amend: true, defaultMsg: msg });
await this.commitWithAnyInput(repository, { all: false, amend: true });
}
@command('git.commitAll', { repository: true })
@@ -1267,25 +1314,26 @@ export class CommandCenter {
return;
}
const picks = remotes.map(r => ({ label: r.name, description: r.url }));
const remotePicks = remotes.map(r => ({ label: r.name, description: r.url }));
const placeHolder = localize('pick remote pull repo', "Pick a remote to pull the branch from");
const pick = await window.showQuickPick(picks, { placeHolder });
const remotePick = await window.showQuickPick(remotePicks, { placeHolder });
if (!pick) {
if (!remotePick) {
return;
}
const branchName = await window.showInputBox({
placeHolder: localize('branch name', "Branch name"),
prompt: localize('provide branch name', "Please provide a branch name"),
ignoreFocusOut: true
});
const remoteRefs = repository.refs;
const remoteRefsFiltered = remoteRefs.filter(r => (r.remote === remotePick.label));
const branchPicks = remoteRefsFiltered.map(r => ({ label: r.name })) as { label: string; description: string }[];
const branchPick = await window.showQuickPick(branchPicks, { placeHolder });
if (!branchName) {
if (!branchPick) {
return;
}
repository.pull(false, pick.label, branchName);
const remoteCharCnt = remotePick.label.length;
repository.pull(false, remotePick.label, branchPick.label.slice(remoteCharCnt + 1));
}
@command('git.pull', { repository: true })
@@ -1321,7 +1369,27 @@ export class CommandCenter {
return;
}
await repository.push();
if (!repository.HEAD || !repository.HEAD.name) {
window.showWarningMessage(localize('nobranch', "Please check out a branch to push to a remote."));
return;
}
try {
await repository.push();
} catch (err) {
if (err.gitErrorCode !== GitErrorCodes.NoUpstreamBranch) {
throw err;
}
const branchName = repository.HEAD.name;
const message = localize('confirm publish branch', "The branch '{0}' has no upstream branch. Would you like to publish this branch?", branchName);
const yes = localize('ok', "OK");
const pick = await window.showWarningMessage(message, { modal: true }, yes);
if (pick === yes) {
await this.publish(repository);
}
}
}
@command('git.pushWithTags', { repository: true })
@@ -1377,7 +1445,7 @@ export class CommandCenter {
if (shouldPrompt) {
const message = localize('sync is unpredictable', "This action will push and pull commits to and from '{0}'.", HEAD.upstream);
const yes = localize('ok', "OK");
const neverAgain = localize('never again', "OK, Never Show Again");
const neverAgain = localize('never again', "OK, Don't Show Again");
const pick = await window.showWarningMessage(message, { modal: true }, yes, neverAgain);
if (pick === neverAgain) {
@@ -1465,7 +1533,10 @@ export class CommandCenter {
}
private async _stash(repository: Repository, includeUntracked = false): Promise<void> {
if (repository.workingTreeGroup.resourceStates.length === 0) {
const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0;
const noStagedChanges = repository.indexGroup.resourceStates.length === 0;
if (noUnstagedChanges && noStagedChanges) {
window.showInformationMessage(localize('no changes stash', "There are no changes to stash."));
return;
}
@@ -1641,13 +1712,18 @@ export class CommandCenter {
const isSingleResource = arg instanceof Uri;
const groups = resources.reduce((result, resource) => {
const repository = this.model.getRepository(resource);
let repository = this.model.getRepository(resource);
if (!repository) {
console.warn('Could not find git repository for ', resource);
return result;
}
// Could it be a submodule?
if (resource.fsPath === repository.root) {
repository = this.model.getRepositoryForSubmodule(resource) || repository;
}
const tuple = result.filter(p => p.repository === repository)[0];
if (tuple) {

View File

@@ -52,7 +52,7 @@ export class GitContentProvider {
return;
}
this._onDidChange.fire(toGitUri(uri, '', true));
this._onDidChange.fire(toGitUri(uri, '', { replaceFileExtension: true }));
}
@debounce(1100)
@@ -83,6 +83,18 @@ export class GitContentProvider {
}
async provideTextDocumentContent(uri: Uri): Promise<string> {
let { path, ref, submoduleOf } = fromGitUri(uri);
if (submoduleOf) {
const repository = this.model.getRepository(submoduleOf);
if (!repository) {
return '';
}
return await repository.diff(path, { cached: ref === 'index' });
}
const repository = this.model.getRepository(uri);
if (!repository) {
@@ -95,8 +107,6 @@ export class GitContentProvider {
this.cache[cacheKey] = cacheValue;
let { path, ref } = fromGitUri(uri);
if (ref === '~') {
const fileUri = Uri.file(path);
const uriString = fileUri.toString();

View File

@@ -6,35 +6,48 @@
'use strict';
import { window, workspace, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode';
import * as path from 'path';
import { Repository, GitResourceGroup, Status } from './repository';
import { Model } from './model';
import { debounce } from './decorators';
import { filterEvent } from './util';
import { filterEvent, dispose, anyEvent, fireEvent } from './util';
import { GitErrorCodes } from './git';
type Callback = { resolve: (status: boolean) => void, reject: (err: any) => void };
class GitIgnoreDecorationProvider implements DecorationProvider {
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
readonly onDidChangeDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
private checkIgnoreQueue = new Map<string, { resolve: (status: boolean) => void, reject: (err: any) => void }>();
readonly onDidChangeDecorations: Event<Uri[]>;
private queue = new Map<string, { repository: Repository; queue: Map<string, Callback>; }>();
private disposables: Disposable[] = [];
constructor(private repository: Repository) {
this.disposables.push(
window.registerDecorationProvider(this),
filterEvent(workspace.onDidSaveTextDocument, e => e.fileName.endsWith('.gitignore'))(_ => this._onDidChangeDecorations.fire())
//todo@joh -> events when the ignore status actually changes, not only when the file changes
);
}
constructor(private model: Model) {
//todo@joh -> events when the ignore status actually changes, not only when the file changes
this.onDidChangeDecorations = fireEvent(anyEvent<any>(
filterEvent(workspace.onDidSaveTextDocument, e => e.fileName.endsWith('.gitignore')),
model.onDidOpenRepository,
model.onDidCloseRepository
));
dispose(): void {
this.disposables.forEach(d => d.dispose());
this.checkIgnoreQueue.clear();
this.disposables.push(window.registerDecorationProvider(this));
}
provideDecoration(uri: Uri): Promise<DecorationData | undefined> {
const repository = this.model.getRepository(uri);
if (!repository) {
return Promise.resolve(undefined);
}
let queueItem = this.queue.get(repository.root);
if (!queueItem) {
queueItem = { repository, queue: new Map<string, Callback>() };
this.queue.set(repository.root, queueItem);
}
return new Promise<boolean>((resolve, reject) => {
this.checkIgnoreQueue.set(uri.fsPath, { resolve, reject });
queueItem!.queue.set(uri.fsPath, { resolve, reject });
this.checkIgnoreSoon();
}).then(ignored => {
if (ignored) {
@@ -48,23 +61,42 @@ class GitIgnoreDecorationProvider implements DecorationProvider {
@debounce(500)
private checkIgnoreSoon(): void {
const queue = new Map(this.checkIgnoreQueue.entries());
this.checkIgnoreQueue.clear();
this.repository.checkIgnore([...queue.keys()]).then(ignoreSet => {
for (const [key, value] of queue.entries()) {
value.resolve(ignoreSet.has(key));
}
}, err => {
console.error(err);
for (const [, value] of queue.entries()) {
value.reject(err);
}
});
const queue = new Map(this.queue.entries());
this.queue.clear();
for (const [, item] of queue) {
const paths = [...item.queue.keys()];
item.repository.checkIgnore(paths).then(ignoreSet => {
for (const [key, value] of item.queue.entries()) {
value.resolve(ignoreSet.has(key));
}
}, err => {
if (err.gitErrorCode !== GitErrorCodes.IsInSubmodule) {
console.error(err);
}
for (const [, value] of item.queue.entries()) {
value.reject(err);
}
});
}
}
dispose(): void {
this.disposables.forEach(d => d.dispose());
this.queue.clear();
}
}
class GitDecorationProvider implements DecorationProvider {
private static SubmoduleDecorationData: DecorationData = {
title: 'Submodule',
abbreviation: 'S',
color: new ThemeColor('gitDecoration.submoduleResourceForeground')
};
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
readonly onDidChangeDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
@@ -80,6 +112,8 @@ class GitDecorationProvider implements DecorationProvider {
private onDidRunGitStatus(): void {
let newDecorations = new Map<string, DecorationData>();
this.collectSubmoduleDecorationData(newDecorations);
this.collectDecorationData(this.repository.indexGroup, newDecorations);
this.collectDecorationData(this.repository.workingTreeGroup, newDecorations);
this.collectDecorationData(this.repository.mergeGroup, newDecorations);
@@ -101,6 +135,12 @@ class GitDecorationProvider implements DecorationProvider {
});
}
private collectSubmoduleDecorationData(bucket: Map<string, DecorationData>): void {
for (const submodule of this.repository.submodules) {
bucket.set(Uri.file(path.join(this.repository.root, submodule.path)).toString(), GitDecorationProvider.SubmoduleDecorationData);
}
}
provideDecoration(uri: Uri): DecorationData | undefined {
return this.decorations.get(uri.toString());
}
@@ -113,17 +153,21 @@ class GitDecorationProvider implements DecorationProvider {
export class GitDecorations {
private configListener: Disposable;
private modelListener: Disposable[] = [];
private disposables: Disposable[] = [];
private modelDisposables: Disposable[] = [];
private providers = new Map<Repository, Disposable>();
constructor(private model: Model) {
this.configListener = workspace.onDidChangeConfiguration(e => e.affectsConfiguration('git.decorations.enabled') && this.update());
this.disposables.push(new GitIgnoreDecorationProvider(model));
const onEnablementChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.decorations.enabled'));
onEnablementChange(this.update, this, this.disposables);
this.update();
}
private update(): void {
const enabled = workspace.getConfiguration('git').get('decorations.enabled');
if (enabled) {
this.enable();
} else {
@@ -132,26 +176,25 @@ export class GitDecorations {
}
private enable(): void {
this.modelListener = [];
this.model.onDidOpenRepository(this.onDidOpenRepository, this, this.modelListener);
this.model.onDidCloseRepository(this.onDidCloseRepository, this, this.modelListener);
this.model.onDidOpenRepository(this.onDidOpenRepository, this, this.modelDisposables);
this.model.onDidCloseRepository(this.onDidCloseRepository, this, this.modelDisposables);
this.model.repositories.forEach(this.onDidOpenRepository, this);
}
private disable(): void {
this.modelListener.forEach(d => d.dispose());
this.modelDisposables = dispose(this.modelDisposables);
this.providers.forEach(value => value.dispose());
this.providers.clear();
}
private onDidOpenRepository(repository: Repository): void {
const provider = new GitDecorationProvider(repository);
const ignoreProvider = new GitIgnoreDecorationProvider(repository);
this.providers.set(repository, Disposable.from(provider, ignoreProvider));
this.providers.set(repository, provider);
}
private onDidCloseRepository(repository: Repository): void {
const provider = this.providers.get(repository);
if (provider) {
provider.dispose();
this.providers.delete(repository);
@@ -159,9 +202,7 @@ export class GitDecorations {
}
dispose(): void {
this.configListener.dispose();
this.modelListener.forEach(d => d.dispose());
this.providers.forEach(value => value.dispose);
this.providers.clear();
this.disable();
this.disposables = dispose(this.disposables);
}
}

View File

@@ -78,7 +78,7 @@ function _throttle<T>(fn: Function, key: string): Function {
export const throttle = decorate(_throttle);
function _sequentialize<T>(fn: Function, key: string): Function {
function _sequentialize(fn: Function, key: string): Function {
const currentKey = `__$sequence$${key}`;
return function (this: any, ...args: any[]) {

View File

@@ -16,7 +16,7 @@ import * as filetype from 'file-type';
import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util';
import { CancellationToken } from 'vscode';
const readfile = denodeify<string>(fs.readFile);
const readfile = denodeify<string, string | null, string>(fs.readFile);
export interface IGit {
path: string;
@@ -267,6 +267,7 @@ export class GitError {
this.message = data.error.message;
} else {
this.error = void 0;
this.message = '';
}
this.message = this.message || data.message || 'Git error';
@@ -325,7 +326,9 @@ export const GitErrorCodes = {
BranchAlreadyExists: 'BranchAlreadyExists',
NoLocalChanges: 'NoLocalChanges',
NoStashFound: 'NoStashFound',
LocalChangesOverwritten: 'LocalChangesOverwritten'
LocalChangesOverwritten: 'LocalChangesOverwritten',
NoUpstreamBranch: 'NoUpstreamBranch',
IsInSubmodule: 'IsInSubmodule'
};
function getGitErrorCode(stderr: string): string | undefined {
@@ -359,7 +362,6 @@ function getGitErrorCode(stderr: string): string | undefined {
export class Git {
private gitPath: string;
private version: string;
private env: any;
private _onOutput = new EventEmitter();
@@ -367,7 +369,6 @@ export class Git {
constructor(options: IGitOptions) {
this.gitPath = options.gitPath;
this.version = options.version;
this.env = options.env || {};
}
@@ -460,7 +461,7 @@ export class Git {
});
if (options.log !== false) {
this.log(`git ${args.join(' ')}\n`);
this.log(`> git ${args.join(' ')}\n`);
}
return cp.spawn(this.gitPath, args, options);
@@ -542,6 +543,72 @@ export class GitStatusParser {
}
}
export interface Submodule {
name: string;
path: string;
url: string;
}
export function parseGitmodules(raw: string): Submodule[] {
const regex = /\r?\n/g;
let position = 0;
let match: RegExpExecArray | null = null;
const result: Submodule[] = [];
let submodule: Partial<Submodule> = {};
function parseLine(line: string): void {
const sectionMatch = /^\s*\[submodule "([^"]+)"\]\s*$/.exec(line);
if (sectionMatch) {
if (submodule.name && submodule.path && submodule.url) {
result.push(submodule as Submodule);
}
const name = sectionMatch[1];
if (name) {
submodule = { name };
return;
}
}
if (!submodule) {
return;
}
const propertyMatch = /^\s*(\w+) = (.*)$/.exec(line);
if (!propertyMatch) {
return;
}
const [, key, value] = propertyMatch;
switch (key) {
case 'path': submodule.path = value; break;
case 'url': submodule.url = value; break;
}
}
while (match = regex.exec(raw)) {
parseLine(raw.substring(position, match.index));
position = match.index + match[0].length;
}
parseLine(raw.substring(position));
if (submodule.name && submodule.path && submodule.url) {
result.push(submodule as Submodule);
}
return result;
}
export interface DiffOptions {
cached?: boolean;
}
export class Repository {
constructor(
@@ -611,7 +678,7 @@ export class Repository {
return stdout;
}
async lstree(treeish: string, path: string): Promise<{ mode: number, object: string, size: number }> {
async lstree(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }> {
if (!treeish) { // index
const { stdout } = await this.run(['ls-files', '--stage', '--', path]);
@@ -625,7 +692,7 @@ export class Repository {
const catFile = await this.run(['cat-file', '-s', object]);
const size = parseInt(catFile.stdout);
return { mode: parseInt(mode), object, size };
return { mode, object, size };
}
const { stdout } = await this.run(['ls-tree', '-l', treeish, '--', path]);
@@ -637,7 +704,7 @@ export class Repository {
}
const [, mode, , object, size] = match;
return { mode: parseInt(mode), object, size: parseInt(size) };
return { mode, object, size: parseInt(size) };
}
async detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }> {
@@ -680,6 +747,19 @@ export class Repository {
}
}
async diff(path: string, options: DiffOptions = {}): Promise<string> {
const args = ['diff'];
if (options.cached) {
args.push('--cached');
}
args.push('--', path);
const result = await this.run(args);
return result.stdout;
}
async add(paths: string[]): Promise<void> {
const args = ['add', '-A', '--'];
@@ -706,7 +786,16 @@ export class Repository {
});
}
await this.run(['update-index', '--cacheinfo', '100644', hash, path]);
let mode: string;
try {
const details = await this.lstree('HEAD', path);
mode = details.mode;
} catch (err) {
mode = '100644';
}
await this.run(['update-index', '--cacheinfo', mode, hash, path]);
}
async checkout(treeish: string, paths: string[]): Promise<void> {
@@ -953,6 +1042,8 @@ export class Repository {
err.gitErrorCode = GitErrorCodes.PushRejected;
} else if (/Could not read from remote repository/.test(err.stderr || '')) {
err.gitErrorCode = GitErrorCodes.RemoteConnectionError;
} else if (/^fatal: The current branch .* has no upstream branch/.test(err.stderr || '')) {
err.gitErrorCode = GitErrorCodes.NoUpstreamBranch;
}
throw err;
@@ -1067,7 +1158,7 @@ export class Repository {
}
async getRefs(): Promise<Ref[]> {
const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)']);
const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)', '--sort', '-committerdate']);
const fn = (line: string): Ref | null => {
let match: RegExpExecArray | null;
@@ -1186,4 +1277,24 @@ export class Repository {
return { hash: match[1], message: match[2] };
}
async updateSubmodules(paths: string[]): Promise<void> {
const args = ['submodule', 'update', '--', ...paths];
await this.run(args);
}
async getSubmodules(): Promise<Submodule[]> {
const gitmodulesPath = path.join(this.root, '.gitmodules');
try {
const gitmodulesRaw = await readfile(gitmodulesPath, 'utf8');
return parseGitmodules(gitmodulesRaw);
} catch (err) {
if (/ENOENT/.test(err.message)) {
return [];
}
throw err;
}
}
}

View File

@@ -6,7 +6,7 @@
'use strict';
import * as nls from 'vscode-nls';
const localize = nls.config(process.env.VSCODE_NLS_CONFIG)();
const localize = nls.loadMessageBundle();
import { ExtensionContext, workspace, window, Disposable, commands, Uri, OutputChannel } from 'vscode';
import { findGit, Git, IGit } from './git';
import { Model } from './model';
@@ -14,21 +14,19 @@ import { CommandCenter } from './commands';
import { GitContentProvider } from './contentProvider';
import { GitDecorations } from './decorationProvider';
import { Askpass } from './askpass';
import { toDisposable } from './util';
import { toDisposable, filterEvent, eventToPromise } from './util';
import TelemetryReporter from 'vscode-extension-telemetry';
import { API, createApi } from './api';
async function init(context: ExtensionContext, outputChannel: OutputChannel, disposables: Disposable[]): Promise<Model> {
const { name, version, aiKey } = require(context.asAbsolutePath('./package.json')) as { name: string, version: string, aiKey: string };
const telemetryReporter: TelemetryReporter = new TelemetryReporter(name, version, aiKey);
disposables.push(telemetryReporter);
let telemetryReporter: TelemetryReporter;
async function init(context: ExtensionContext, outputChannel: OutputChannel, disposables: Disposable[]): Promise<Model> {
const pathHint = workspace.getConfiguration('git').get<string>('path');
const info = await findGit(pathHint, path => outputChannel.appendLine(localize('looking', "Looking for git in: {0}", path)));
const askpass = new Askpass();
const env = await askpass.getEnv();
const git = new Git({ gitPath: info.path, version: info.version, env });
const model = new Model(git, context.globalState);
const model = new Model(git, context.globalState, outputChannel);
disposables.push(model);
const onRepository = () => commands.executeCommand('setContext', 'gitOpenRepositoryCount', `${model.repositories.length}`);
@@ -38,7 +36,15 @@ async function init(context: ExtensionContext, outputChannel: OutputChannel, dis
outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path));
const onOutput = (str: string) => outputChannel.append(str);
const onOutput = (str: string) => {
const lines = str.split(/\r?\n/mg);
while (/^\s*$/.test(lines[lines.length - 1])) {
lines.pop();
}
outputChannel.appendLine(lines.join('\n'));
};
git.onOutput.addListener('log', onOutput);
disposables.push(toDisposable(() => git.onOutput.removeListener('log', onOutput)));
@@ -77,7 +83,7 @@ async function _activate(context: ExtensionContext, disposables: Disposable[]):
outputChannel.show();
const download = localize('downloadgit', "Download Git");
const neverShowAgain = localize('neverShowAgain', "Don't show again");
const neverShowAgain = localize('neverShowAgain', "Don't Show Again");
const choice = await window.showWarningMessage(
localize('notfound', "Git not found. Install it or configure it using the 'git.path' setting."),
download,
@@ -93,11 +99,30 @@ async function _activate(context: ExtensionContext, disposables: Disposable[]):
}
export function activate(context: ExtensionContext): API {
const config = workspace.getConfiguration('git', null);
const enabled = config.get<boolean>('enabled');
const disposables: Disposable[] = [];
context.subscriptions.push(new Disposable(() => Disposable.from(...disposables).dispose()));
const activatePromise = _activate(context, disposables);
const modelPromise = activatePromise.then(model => model || Promise.reject<Model>('Git model not found'));
const { name, version, aiKey } = require(context.asAbsolutePath('./package.json')) as { name: string, version: string, aiKey: string };
telemetryReporter = new TelemetryReporter(name, version, aiKey);
let activatePromise: Promise<Model | undefined>;
if (enabled) {
activatePromise = _activate(context, disposables);
} else {
const onConfigChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git'));
const onEnabled = filterEvent(onConfigChange, () => workspace.getConfiguration('git', null).get<boolean>('enabled') === true);
activatePromise = eventToPromise(onEnabled)
.then(() => _activate(context, disposables));
}
const modelPromise = activatePromise
.then(model => model || Promise.reject<Model>('Git model not found'));
activatePromise.catch(err => console.error(err));
return createApi(modelPromise);
@@ -123,7 +148,7 @@ async function checkGitVersion(info: IGit): Promise<void> {
}
const update = localize('updateGit', "Update Git");
const neverShowAgain = localize('neverShowAgain', "Don't show again");
const neverShowAgain = localize('neverShowAgain', "Don't Show Again");
const choice = await window.showWarningMessage(
localize('git20', "You seem to have git {0} installed. Code works best with git >= 2", info.version),
@@ -139,3 +164,7 @@ async function checkGitVersion(info: IGit): Promise<void> {
// {{SQL CARBON EDIT}}
*/
}
export function deactivate(): Promise<any> {
return telemetryReporter ? telemetryReporter.dispose() : Promise.resolve(null);
}

View File

@@ -5,10 +5,10 @@
'use strict';
import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, ConfigurationChangeEvent } from 'vscode';
import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, OutputChannel } from 'vscode';
import { Repository, RepositoryState } from './repository';
import { memoize, sequentialize, debounce } from './decorators';
import { dispose, anyEvent, filterEvent, IDisposable, isDescendant } from './util';
import { dispose, anyEvent, filterEvent, isDescendant, firstIndex } from './util';
import { Git, GitErrorCodes } from './git';
import * as path from 'path';
import * as fs from 'fs';
@@ -28,7 +28,7 @@ class RepositoryPick implements QuickPickItem {
.join(' ');
}
constructor(public readonly repository: Repository) { }
constructor(public readonly repository: Repository, public readonly index: number) { }
}
export interface ModelChangeEvent {
@@ -66,7 +66,7 @@ export class Model {
private disposables: Disposable[] = [];
constructor(private git: Git, private globalState: Memento) {
constructor(private git: Git, private globalState: Memento, private outputChannel: OutputChannel) {
workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables);
this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] });
@@ -93,17 +93,25 @@ export class Model {
private async scanWorkspaceFolders(): Promise<void> {
for (const folder of workspace.workspaceFolders || []) {
const root = folder.uri.fsPath;
const children = await new Promise<string[]>((c, e) => fs.readdir(root, (err, r) => err ? e(err) : c(r)));
children
.filter(child => child !== '.git')
.forEach(child => this.tryOpenRepository(path.join(root, child)));
try {
const children = await new Promise<string[]>((c, e) => fs.readdir(root, (err, r) => err ? e(err) : c(r)));
children
.filter(child => child !== '.git')
.forEach(child => this.tryOpenRepository(path.join(root, child)));
} catch (err) {
// noop
}
}
}
private onPossibleGitRepositoryChange(uri: Uri): void {
const possibleGitRepositoryPath = uri.fsPath.replace(/\.git.*$/, '');
this.possibleGitRepositoryPaths.add(possibleGitRepositoryPath);
this.eventuallyScanPossibleGitRepository(uri.fsPath.replace(/\.git.*$/, ''));
}
private eventuallyScanPossibleGitRepository(path: string) {
this.possibleGitRepositoryPaths.add(path);
this.eventuallyScanPossibleGitRepositories();
}
@@ -150,6 +158,13 @@ export class Model {
}
private onDidChangeVisibleTextEditors(editors: TextEditor[]): void {
const config = workspace.getConfiguration('git');
const enabled = config.get<boolean>('autoRepositoryDetection') === true;
if (!enabled) {
return;
}
editors.forEach(editor => {
const uri = editor.document.uri;
@@ -181,11 +196,13 @@ export class Model {
}
try {
const repositoryRoot = await this.git.getRepositoryRoot(path);
const rawRoot = await this.git.getRepositoryRoot(path);
// This can happen whenever `path` has the wrong case sensitivity in
// case insensitive file systems
// https://github.com/Microsoft/vscode/issues/33498
const repositoryRoot = Uri.file(rawRoot).fsPath;
if (this.getRepository(repositoryRoot)) {
return;
}
@@ -203,15 +220,31 @@ export class Model {
}
private open(repository: Repository): void {
this.outputChannel.appendLine(`Open repository: ${repository.root}`);
const onDidDisappearRepository = filterEvent(repository.onDidChangeState, state => state === RepositoryState.Disposed);
const disappearListener = onDidDisappearRepository(() => dispose());
const changeListener = repository.onDidChangeRepository(uri => this._onDidChangeRepository.fire({ repository, uri }));
const originalResourceChangeListener = repository.onDidChangeOriginalResource(uri => this._onDidChangeOriginalResource.fire({ repository, uri }));
const checkForSubmodules = () => {
if (repository.submodules.length > 10) {
window.showWarningMessage(localize('too many submodules', "The '{0}' repository has {1} submodules which won't be opened automatically. You can still open each one individually by opening a file within.", path.basename(repository.root), repository.submodules.length));
statusListener.dispose();
return;
}
this.scanSubmodules(repository);
};
const statusListener = repository.onDidRunGitStatus(checkForSubmodules);
checkForSubmodules();
const dispose = () => {
disappearListener.dispose();
changeListener.dispose();
originalResourceChangeListener.dispose();
statusListener.dispose();
repository.dispose();
this.openRepositories = this.openRepositories.filter(e => e !== openRepository);
@@ -223,6 +256,20 @@ export class Model {
this._onDidOpenRepository.fire(repository);
}
private scanSubmodules(repository: Repository): void {
const shouldScanSubmodules = workspace
.getConfiguration('git', Uri.file(repository.root))
.get<boolean>('detectSubmodules') === true;
if (!shouldScanSubmodules) {
return;
}
repository.submodules
.map(r => path.join(repository.root, r.path))
.forEach(p => this.eventuallyScanPossibleGitRepository(p));
}
close(repository: Repository): void {
const openRepository = this.getOpenRepository(repository);
@@ -230,6 +277,7 @@ export class Model {
return;
}
this.outputChannel.appendLine(`Close repository: ${repository.root}`);
openRepository.dispose();
}
@@ -238,7 +286,16 @@ export class Model {
throw new Error(localize('no repositories', "There are no available repositories"));
}
const picks = this.openRepositories.map(e => new RepositoryPick(e.repository));
const picks = this.openRepositories.map((e, index) => new RepositoryPick(e.repository, index));
const active = window.activeTextEditor;
const repository = active && this.getRepository(active.document.fileName);
const index = firstIndex(picks, pick => pick.repository === repository);
// Move repository pick containing the active text editor to appear first
if (index > -1) {
picks.unshift(...picks.splice(index, 1));
}
const placeHolder = localize('pick repo', "Choose a repository");
const pick = await window.showQuickPick(picks, { placeHolder });
@@ -281,12 +338,21 @@ export class Model {
resourcePath = hint.fsPath;
}
for (const liveRepository of this.openRepositories) {
const relativePath = path.relative(liveRepository.repository.root, resourcePath);
if (isDescendant(liveRepository.repository.root, resourcePath)) {
return liveRepository;
outer:
for (const liveRepository of this.openRepositories.sort((a, b) => b.repository.root.length - a.repository.root.length)) {
if (!isDescendant(liveRepository.repository.root, resourcePath)) {
continue;
}
for (const submodule of liveRepository.repository.submodules) {
const submoduleRoot = path.join(liveRepository.repository.root, submodule.path);
if (isDescendant(submoduleRoot, resourcePath)) {
continue outer;
}
}
return liveRepository;
}
return undefined;
@@ -307,6 +373,20 @@ export class Model {
return undefined;
}
getRepositoryForSubmodule(submoduleUri: Uri): Repository | undefined {
for (const repository of this.repositories) {
for (const submodule of repository.submodules) {
const submodulePath = path.join(repository.root, submodule.path);
if (submodulePath === submoduleUri.fsPath) {
return repository;
}
}
}
return undefined;
}
dispose(): void {
const openRepositories = [...this.openRepositories];
openRepositories.forEach(r => r.dispose());

View File

@@ -5,9 +5,9 @@
'use strict';
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento } from 'vscode';
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git';
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant } from './util';
import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType } from 'vscode';
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError, Submodule, DiffOptions } from './git';
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent } from './util';
import { memoize, throttle, debounce } from './decorators';
import { toGitUri } from './uri';
import { AutoFetcher } from './autofetch';
@@ -105,7 +105,7 @@ export class Resource implements SourceControlResourceState {
}
};
private getIconPath(theme: string): Uri | undefined {
private getIconPath(theme: string): Uri {
switch (this.type) {
case Status.INDEX_MODIFIED: return Resource.Icons[theme].Modified;
case Status.MODIFIED: return Resource.Icons[theme].Modified;
@@ -123,7 +123,6 @@ export class Resource implements SourceControlResourceState {
case Status.DELETED_BY_US: return Resource.Icons[theme].Conflict;
case Status.BOTH_ADDED: return Resource.Icons[theme].Conflict;
case Status.BOTH_MODIFIED: return Resource.Icons[theme].Conflict;
default: return void 0;
}
}
@@ -182,7 +181,7 @@ export class Resource implements SourceControlResourceState {
return { strikeThrough, faded, tooltip, light, dark, letter, color, source: 'git.resource' /*todo@joh*/ };
}
get letter(): string | undefined {
get letter(): string {
switch (this.type) {
case Status.INDEX_MODIFIED:
case Status.MODIFIED:
@@ -207,12 +206,10 @@ export class Resource implements SourceControlResourceState {
case Status.BOTH_ADDED:
case Status.BOTH_MODIFIED:
return 'C';
default:
return undefined;
}
}
get color(): ThemeColor | undefined {
get color(): ThemeColor {
switch (this.type) {
case Status.INDEX_MODIFIED:
case Status.MODIFIED:
@@ -235,8 +232,6 @@ export class Resource implements SourceControlResourceState {
case Status.BOTH_ADDED:
case Status.BOTH_MODIFIED:
return new ThemeColor('gitDecoration.conflictingResourceForeground');
default:
return undefined;
}
}
@@ -261,7 +256,7 @@ export class Resource implements SourceControlResourceState {
}
}
get resourceDecoration(): DecorationData | undefined {
get resourceDecoration(): DecorationData {
const title = this.tooltip;
const abbreviation = this.letter;
const color = this.color;
@@ -280,6 +275,7 @@ export class Resource implements SourceControlResourceState {
export enum Operation {
Status = 'Status',
Diff = 'Diff',
Add = 'Add',
RevertFiles = 'RevertFiles',
Commit = 'Commit',
@@ -301,7 +297,8 @@ export enum Operation {
Tag = 'Tag',
Stash = 'Stash',
CheckIgnore = 'CheckIgnore',
LSTree = 'LSTree'
LSTree = 'LSTree',
SubmoduleUpdate = 'SubmoduleUpdate'
}
function isReadOnly(operation: Operation): boolean {
@@ -330,6 +327,7 @@ function shouldShowProgress(operation: Operation): boolean {
export interface Operations {
isIdle(): boolean;
shouldShowProgress(): boolean;
isRunning(operation: Operation): boolean;
}
@@ -366,6 +364,18 @@ class OperationsImpl implements Operations {
return true;
}
shouldShowProgress(): boolean {
const operations = this.operations.keys();
for (const operation of operations) {
if (shouldShowProgress(operation)) {
return true;
}
}
return false;
}
}
export interface CommitOptions {
@@ -373,7 +383,6 @@ export interface CommitOptions {
amend?: boolean;
signoff?: boolean;
signCommit?: boolean;
defaultMsg?: string;
}
export interface GitResourceGroup extends SourceControlResourceGroup {
@@ -385,8 +394,33 @@ export interface OperationResult {
error: any;
}
class ProgressManager {
private disposable: IDisposable = EmptyDisposable;
constructor(repository: Repository) {
const start = onceEvent(filterEvent(repository.onDidChangeOperations, () => repository.operations.shouldShowProgress()));
const end = onceEvent(filterEvent(debounceEvent(repository.onDidChangeOperations, 300), () => !repository.operations.shouldShowProgress()));
const setup = () => {
this.disposable = start(() => {
const promise = eventToPromise(end).then(() => setup());
window.withProgress({ location: ProgressLocation.SourceControl }, () => promise);
});
};
setup();
}
dispose(): void {
this.disposable.dispose();
}
}
export class Repository implements Disposable {
private static readonly InputValidationLength = 72;
private _onDidChangeRepository = new EventEmitter<Uri>();
readonly onDidChangeRepository: Event<Uri> = this._onDidChangeRepository.event;
@@ -439,6 +473,11 @@ export class Repository implements Disposable {
return this._remotes;
}
private _submodules: Submodule[] = [];
get submodules(): Submodule[] {
return this._submodules;
}
private _operations = new OperationsImpl();
get operations(): Operations { return this._operations; }
@@ -474,7 +513,7 @@ export class Repository implements Disposable {
const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete);
const onRepositoryChange = filterEvent(onWorkspaceChange, uri => isDescendant(repository.root, uri.fsPath));
const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.git\/index\.lock$/.test(uri.path));
const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.git(\/index\.lock)?$/.test(uri.path));
onRelevantRepositoryChange(this.onFSChange, this, this.disposables);
const onRelevantGitChange = filterEvent(onRelevantRepositoryChange, uri => /\/\.git\//.test(uri.path));
@@ -484,6 +523,7 @@ export class Repository implements Disposable {
this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message (press {0} to commit)");
this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] };
this._sourceControl.quickDiffProvider = this;
this._sourceControl.inputBox.validateInput = this.validateInput.bind(this);
this.disposables.push(this._sourceControl);
this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "Merge Changes"));
@@ -504,16 +544,56 @@ export class Repository implements Disposable {
statusBar.onDidChange(() => this._sourceControl.statusBarCommands = statusBar.commands, null, this.disposables);
this._sourceControl.statusBarCommands = statusBar.commands;
const progressManager = new ProgressManager(this);
this.disposables.push(progressManager);
this.updateCommitTemplate();
this.status();
}
validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined {
const config = workspace.getConfiguration('git');
const setting = config.get<'always' | 'warn' | 'off'>('inputValidation');
if (setting === 'off') {
return;
}
let start = 0, end;
let match: RegExpExecArray | null;
const regex = /\r?\n/g;
while ((match = regex.exec(text)) && position > match.index) {
start = match.index + match[0].length;
}
end = match ? match.index : text.length;
const line = text.substring(start, end);
if (line.length <= Repository.InputValidationLength) {
if (setting !== 'always') {
return;
}
return {
message: localize('commitMessageCountdown', "{0} characters left in current line", Repository.InputValidationLength - line.length),
type: SourceControlInputBoxValidationType.Information
};
} else {
return {
message: localize('commitMessageWarning', "{0} characters over {1} in current line", line.length - Repository.InputValidationLength, Repository.InputValidationLength),
type: SourceControlInputBoxValidationType.Warning
};
}
}
provideOriginalResource(uri: Uri): Uri | undefined {
if (uri.scheme !== 'file') {
return;
}
return toGitUri(uri, '', true);
return toGitUri(uri, '', { replaceFileExtension: true });
}
private async updateCommitTemplate(): Promise<void> {
@@ -524,21 +604,15 @@ export class Repository implements Disposable {
}
}
// @throttle
// async init(): Promise<void> {
// if (this.state !== State.NotAGitRepository) {
// return;
// }
// await this.git.init(this.workspaceRoot.fsPath);
// await this.status();
// }
@throttle
async status(): Promise<void> {
await this.run(Operation.Status);
}
diff(path: string, options: DiffOptions = {}): Promise<string> {
return this.run(Operation.Diff, () => this.repository.diff(path, options));
}
async add(resources: Uri[]): Promise<void> {
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath)));
}
@@ -567,8 +641,18 @@ export class Repository implements Disposable {
await this.run(Operation.Clean, async () => {
const toClean: string[] = [];
const toCheckout: string[] = [];
const submodulesToUpdate: string[] = [];
resources.forEach(r => {
const fsPath = r.fsPath;
for (const submodule of this.submodules) {
if (path.join(this.root, submodule.path) === fsPath) {
submodulesToUpdate.push(fsPath);
return;
}
}
const raw = r.toString();
const scmResource = find(this.workingTreeGroup.resourceStates, sr => sr.resourceUri.toString() === raw);
@@ -579,11 +663,11 @@ export class Repository implements Disposable {
switch (scmResource.type) {
case Status.UNTRACKED:
case Status.IGNORED:
toClean.push(r.fsPath);
toClean.push(fsPath);
break;
default:
toCheckout.push(r.fsPath);
toCheckout.push(fsPath);
break;
}
});
@@ -598,6 +682,10 @@ export class Repository implements Disposable {
promises.push(this.repository.checkout('', toCheckout));
}
if (submodulesToUpdate.length > 0) {
promises.push(this.repository.updateSubmodules(submodulesToUpdate));
}
await Promise.all(promises);
});
}
@@ -702,15 +790,15 @@ export class Repository implements Disposable {
async buffer(ref: string, filePath: string): Promise<Buffer> {
return await this.run(Operation.Show, async () => {
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
const encoding = configFiles.get<string>('encoding');
// const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
// const encoding = configFiles.get<string>('encoding');
// TODO@joao: REsource config api
return await this.repository.buffer(`${ref}:${relativePath}`);
});
}
lstree(ref: string, filePath: string): Promise<{ mode: number, object: string, size: number }> {
lstree(ref: string, filePath: string): Promise<{ mode: string, object: string, size: number }> {
return this.run(Operation.LSTree, () => this.repository.lstree(ref, filePath));
}
@@ -780,7 +868,11 @@ export class Repository implements Disposable {
// paths are separated by the null-character
resolve(new Set<string>(data.split('\0')));
} else {
reject(new GitError({ stdout: data, stderr, exitCode }));
if (/ is in submodule /.test(stderr)) {
reject(new GitError({ stdout: data, stderr, exitCode, gitErrorCode: GitErrorCodes.IsInSubmodule }));
} else {
reject(new GitError({ stdout: data, stderr, exitCode }));
}
}
};
@@ -807,37 +899,31 @@ export class Repository implements Disposable {
throw new Error('Repository not initialized');
}
const run = async () => {
let error: any = null;
let error: any = null;
this._operations.start(operation);
this._onRunOperation.fire(operation);
this._operations.start(operation);
this._onRunOperation.fire(operation);
try {
const result = await this.retryRun(runOperation);
try {
const result = await this.retryRun(runOperation);
if (!isReadOnly(operation)) {
await this.updateModelState();
}
return result;
} catch (err) {
error = err;
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
this.state = RepositoryState.Disposed;
}
throw err;
} finally {
this._operations.end(operation);
this._onDidRunOperation.fire({ operation, error });
if (!isReadOnly(operation)) {
await this.updateModelState();
}
};
return shouldShowProgress(operation)
? window.withProgress({ location: ProgressLocation.SourceControl }, run)
: run();
return result;
} catch (err) {
error = err;
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
this.state = RepositoryState.Disposed;
}
throw err;
} finally {
this._operations.end(operation);
this._onDidRunOperation.fire({ operation, error });
}
}
private async retryRun<T>(runOperation: () => Promise<T> = () => Promise.resolve<any>(null)): Promise<T> {
@@ -868,10 +954,9 @@ export class Repository implements Disposable {
this.isRepositoryHuge = didHitLimit;
if (didHitLimit && !shouldIgnore && !this.didWarnAboutLimit) {
const ok = { title: localize('ok', "OK"), isCloseAffordance: true };
const neverAgain = { title: localize('neveragain', "Never Show Again") };
const neverAgain = { title: localize('neveragain', "Don't Show Again") };
window.showWarningMessage(localize('huge', "The git repository at '{0}' has too many active changes, only a subset of Git features will be enabled.", this.repository.root), ok, neverAgain).then(result => {
window.showWarningMessage(localize('huge', "The git repository at '{0}' has too many active changes, only a subset of Git features will be enabled.", this.repository.root), neverAgain).then(result => {
if (result === neverAgain) {
config.update('ignoreLimitWarning', true, false);
}
@@ -896,11 +981,12 @@ export class Repository implements Disposable {
// noop
}
const [refs, remotes] = await Promise.all([this.repository.getRefs(), this.repository.getRemotes()]);
const [refs, remotes, submodules] = await Promise.all([this.repository.getRefs(), this.repository.getRemotes(), this.repository.getSubmodules()]);
this._HEAD = HEAD;
this._refs = refs;
this._remotes = remotes;
this._submodules = submodules;
const index: Resource[] = [];
const workingTree: Resource[] = [];
@@ -922,10 +1008,8 @@ export class Repository implements Disposable {
case 'UU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
}
let isModifiedInIndex = false;
switch (raw.x) {
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); isModifiedInIndex = true; break;
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;
@@ -954,13 +1038,9 @@ export class Repository implements Disposable {
this._sourceControl.count = count;
// set context key
let stateContextKey = '';
switch (this.state) {
case RepositoryState.Idle: stateContextKey = 'idle'; break;
case RepositoryState.Disposed: stateContextKey = 'norepo'; break;
}
// Disable `Discard All Changes` for "fresh" repositories
// https://github.com/Microsoft/vscode/issues/43066
commands.executeCommand('setContext', 'gitFreshRepository', !this._HEAD || !this._HEAD.commit);
this._onDidChangeStatus.fire();
}

View File

@@ -72,10 +72,16 @@ export function toLineRanges(selections: Selection[], textDocument: TextDocument
return result;
}
function getModifiedRange(textDocument: TextDocument, diff: LineChange): Range {
return diff.modifiedEndLineNumber === 0
? new Range(textDocument.lineAt(diff.modifiedStartLineNumber - 1).range.end, textDocument.lineAt(diff.modifiedStartLineNumber).range.start)
: new Range(textDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, textDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end);
export function getModifiedRange(textDocument: TextDocument, diff: LineChange): Range {
if (diff.modifiedEndLineNumber === 0) {
if (diff.modifiedStartLineNumber === 0) {
return new Range(textDocument.lineAt(diff.modifiedStartLineNumber).range.end, textDocument.lineAt(diff.modifiedStartLineNumber).range.start);
} else {
return new Range(textDocument.lineAt(diff.modifiedStartLineNumber - 1).range.end, textDocument.lineAt(diff.modifiedStartLineNumber).range.start);
}
} else {
return new Range(textDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, textDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end);
}
}
export function intersectDiffWithRange(textDocument: TextDocument, diff: LineChange, range: Range): LineChange | null {

View File

@@ -6,7 +6,7 @@
'use strict';
import 'mocha';
import { GitStatusParser } from '../git';
import { GitStatusParser, parseGitmodules } from '../git';
import * as assert from 'assert';
suite('git', () => {
@@ -135,4 +135,44 @@ suite('git', () => {
]);
});
});
suite('parseGitmodules', () => {
test('empty', () => {
assert.deepEqual(parseGitmodules(''), []);
});
test('sample', () => {
const sample = `[submodule "deps/spdlog"]
path = deps/spdlog
url = https://github.com/gabime/spdlog.git
`;
assert.deepEqual(parseGitmodules(sample), [
{ name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' }
]);
});
test('big', () => {
const sample = `[submodule "deps/spdlog"]
path = deps/spdlog
url = https://github.com/gabime/spdlog.git
[submodule "deps/spdlog2"]
path = deps/spdlog2
url = https://github.com/gabime/spdlog.git
[submodule "deps/spdlog3"]
path = deps/spdlog3
url = https://github.com/gabime/spdlog.git
[submodule "deps/spdlog4"]
path = deps/spdlog4
url = https://github.com/gabime/spdlog4.git
`;
assert.deepEqual(parseGitmodules(sample), [
{ name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' },
{ name: 'deps/spdlog2', path: 'deps/spdlog2', url: 'https://github.com/gabime/spdlog.git' },
{ name: 'deps/spdlog3', path: 'deps/spdlog3', url: 'https://github.com/gabime/spdlog.git' },
{ name: 'deps/spdlog4', path: 'deps/spdlog4', url: 'https://github.com/gabime/spdlog4.git' }
]);
});
});
});

View File

@@ -7,20 +7,45 @@
import { Uri } from 'vscode';
export function fromGitUri(uri: Uri): { path: string; ref: string; } {
export interface GitUriParams {
path: string;
ref: string;
submoduleOf?: string;
}
export function fromGitUri(uri: Uri): GitUriParams {
return JSON.parse(uri.query);
}
export interface GitUriOptions {
replaceFileExtension?: boolean;
submoduleOf?: string;
}
// As a mitigation for extensions like ESLint showing warnings and errors
// for git URIs, let's change the file extension of these uris to .git,
// when `replaceFileExtension` is true.
export function toGitUri(uri: Uri, ref: string, replaceFileExtension = false): Uri {
export function toGitUri(uri: Uri, ref: string, options: GitUriOptions = {}): Uri {
const params: GitUriParams = {
path: uri.fsPath,
ref
};
if (options.submoduleOf) {
params.submoduleOf = options.submoduleOf;
}
let path = uri.path;
if (options.replaceFileExtension) {
path = `${path}.git`;
} else if (options.submoduleOf) {
path = `${path}.diff`;
}
return uri.with({
scheme: 'git',
path: replaceFileExtension ? `${uri.path}.git` : uri.path,
query: JSON.stringify({
path: uri.fsPath,
ref
})
path,
query: JSON.stringify(params)
});
}

View File

@@ -34,6 +34,10 @@ export function combinedDisposable(disposables: IDisposable[]): IDisposable {
export const EmptyDisposable = toDisposable(() => null);
export function fireEvent<T>(event: Event<T>): Event<T> {
return (listener, thisArgs = null, disposables?) => event(_ => listener.call(thisArgs), null, disposables);
}
export function mapEvent<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
}
@@ -69,6 +73,16 @@ export function onceEvent<T>(event: Event<T>): Event<T> {
};
}
export function debounceEvent<T>(event: Event<T>, delay: number): Event<T> {
return (listener, thisArgs = null, disposables?) => {
let timer: NodeJS.Timer;
return event(e => {
clearTimeout(timer);
timer = setTimeout(() => listener.call(thisArgs, e), delay);
}, null, disposables);
};
}
export function eventToPromise<T>(event: Event<T>): Promise<T> {
return new Promise<T>(c => onceEvent(event)(c));
}
@@ -116,6 +130,10 @@ export function groupBy<T>(arr: T[], fn: (el: T) => string): { [key: string]: T[
}, Object.create(null));
}
export function denodeify<A, B, C, R>(fn: Function): (a: A, b: B, c: C) => Promise<R>;
export function denodeify<A, B, R>(fn: Function): (a: A, b: B) => Promise<R>;
export function denodeify<A, R>(fn: Function): (a: A) => Promise<R>;
export function denodeify<R>(fn: Function): (...args: any[]) => Promise<R>;
export function denodeify<R>(fn: Function): (...args: any[]) => Promise<R> {
return (...args) => new Promise<R>((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r)));
}
@@ -177,6 +195,16 @@ export function uniqueFilter<T>(keyFn: (t: T) => string): (t: T) => boolean {
};
}
export function firstIndex<T>(array: T[], fn: (t: T) => boolean): number {
for (let i = 0; i < array.length; i++) {
if (fn(array[i])) {
return i;
}
}
return -1;
}
export function find<T>(array: T[], fn: (t: T) => boolean): T | undefined {
let result: T | undefined = undefined;
@@ -211,7 +239,7 @@ export async function grep(filename: string, pattern: RegExp): Promise<boolean>
export function readBytes(stream: Readable, bytes: number): Promise<Buffer> {
return new Promise<Buffer>((complete, error) => {
let done = false;
let buffer = new Buffer(bytes);
let buffer = Buffer.allocUnsafe(bytes);
let bytesRead = 0;
stream.on('data', (data: Buffer) => {

View File

@@ -0,0 +1,160 @@
{
"information_for_contributors": [
"This file has been converted from https://github.com/textmate/diff.tmbundle/blob/master/Syntaxes/Diff.plist",
"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/textmate/diff.tmbundle/commit/0593bb775eab1824af97ef2172fd38822abd97d7",
"name": "Diff",
"scopeName": "source.diff",
"patterns": [
{
"captures": {
"1": {
"name": "punctuation.definition.separator.diff"
}
},
"match": "^((\\*{15})|(={67})|(-{3}))$\\n?",
"name": "meta.separator.diff"
},
{
"match": "^\\d+(,\\d+)*(a|d|c)\\d+(,\\d+)*$\\n?",
"name": "meta.diff.range.normal"
},
{
"captures": {
"1": {
"name": "punctuation.definition.range.diff"
},
"2": {
"name": "meta.toc-list.line-number.diff"
},
"3": {
"name": "punctuation.definition.range.diff"
}
},
"match": "^(@@)\\s*(.+?)\\s*(@@)($\\n?)?",
"name": "meta.diff.range.unified"
},
{
"captures": {
"3": {
"name": "punctuation.definition.range.diff"
},
"4": {
"name": "punctuation.definition.range.diff"
},
"6": {
"name": "punctuation.definition.range.diff"
},
"7": {
"name": "punctuation.definition.range.diff"
}
},
"match": "^(((\\-{3}) .+ (\\-{4}))|((\\*{3}) .+ (\\*{4})))$\\n?",
"name": "meta.diff.range.context"
},
{
"match": "^diff --git a/.*$\\n?",
"name": "meta.diff.header.git"
},
{
"match": "^diff (-|\\S+\\s+\\S+).*$\\n?",
"name": "meta.diff.header.command"
},
{
"captures": {
"4": {
"name": "punctuation.definition.from-file.diff"
},
"6": {
"name": "punctuation.definition.from-file.diff"
},
"7": {
"name": "punctuation.definition.from-file.diff"
}
},
"match": "(^(((-{3}) .+)|((\\*{3}) .+))$\\n?|^(={4}) .+(?= - ))",
"name": "meta.diff.header.from-file"
},
{
"captures": {
"2": {
"name": "punctuation.definition.to-file.diff"
},
"3": {
"name": "punctuation.definition.to-file.diff"
},
"4": {
"name": "punctuation.definition.to-file.diff"
}
},
"match": "(^(\\+{3}) .+$\\n?| (-) .* (={4})$\\n?)",
"name": "meta.diff.header.to-file"
},
{
"captures": {
"3": {
"name": "punctuation.definition.inserted.diff"
},
"6": {
"name": "punctuation.definition.inserted.diff"
}
},
"match": "^(((>)( .*)?)|((\\+).*))$\\n?",
"name": "markup.inserted.diff"
},
{
"captures": {
"1": {
"name": "punctuation.definition.changed.diff"
}
},
"match": "^(!).*$\\n?",
"name": "markup.changed.diff"
},
{
"captures": {
"3": {
"name": "punctuation.definition.deleted.diff"
},
"6": {
"name": "punctuation.definition.deleted.diff"
}
},
"match": "^(((<)( .*)?)|((-).*))$\\n?",
"name": "markup.deleted.diff"
},
{
"begin": "^(#)",
"captures": {
"1": {
"name": "punctuation.definition.comment.diff"
}
},
"comment": "Git produces unified diffs with embedded comments\"",
"end": "\\n",
"name": "comment.line.number-sign.diff"
},
{
"match": "^index [0-9a-f]{7,40}\\.\\.[0-9a-f]{7,40}.*$\\n?",
"name": "meta.diff.index.git"
},
{
"captures": {
"1": {
"name": "punctuation.separator.key-value.diff"
},
"2": {
"name": "meta.toc-list.file-name.diff"
}
},
"match": "^Index(:) (.+)$\\n?",
"name": "meta.diff.index"
},
{
"match": "^Only in .*: .*$\\n?",
"name": "meta.diff.only-in"
}
]
}

View File

@@ -0,0 +1,141 @@
{
"information_for_contributors": [
"This file has been converted from https://github.com/textmate/git.tmbundle/blob/master/Syntaxes/Git%20Commit%20Message.tmLanguage",
"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/textmate/git.tmbundle/commit/93897a78c6e52bef13dadc0d4091d203c5facb40",
"name": "Git Commit Message",
"scopeName": "text.git-commit",
"patterns": [
{
"begin": "\\A(?!# Please enter the commit message)",
"end": "^(?=# Please enter the commit message)",
"name": "meta.scope.message.git-commit",
"patterns": [
{
"begin": "\\A(?=#)",
"end": "^(?!#)",
"patterns": [
{
"include": "#comment"
}
]
},
{
"begin": "^(?!# Please enter the commit message)",
"end": "^(?=# Please enter the commit message)",
"patterns": [
{
"begin": "\\G",
"end": "^(?!\\G)",
"name": "meta.scope.subject.git-commit",
"patterns": [
{
"captures": {
"1": {
"name": "keyword.other.$2.git-commit"
}
},
"match": "\\G((fixup|squash)!)\\s*"
},
{
"match": ".{73,}$",
"name": "invalid.illegal.line-too-long.git-commit"
},
{
"match": ".{51,}$",
"name": "invalid.deprecated.line-too-long.git-commit"
}
]
},
{
"begin": "^(?!# Please enter the commit message)",
"end": "^(?=# Please enter the commit message)",
"patterns": [
{
"include": "#comment"
}
]
}
]
}
]
},
{
"begin": "^(?=# Please enter the commit message)",
"end": "\\z",
"name": "meta.scope.metadata.git-commit",
"patterns": [
{
"include": "#metadata"
}
]
}
],
"repository": {
"comment": {
"begin": "^(#)",
"captures": {
"1": {
"name": "punctuation.definition.comment.git-commit"
}
},
"end": "\\n",
"name": "comment.line.number-sign.git-commit"
},
"metadata": {
"patterns": [
{
"begin": "(?=^# Changes to be committed:)",
"end": "(?!\\G)((?=^# \\w)|(?!^#))",
"patterns": [
{
"begin": "(^[ \\t]+)?(?=#)",
"beginCaptures": {
"1": {
"name": "punctuation.whitespace.comment.leading.git-commit"
}
},
"contentName": "comment.line.number-sign.git-commit",
"end": "(?!\\G)^",
"patterns": [
{
"match": "\\G#",
"name": "punctuation.definition.comment.git-commit"
},
{
"match": "((modified|renamed):.*)$\\n?",
"name": "markup.changed.git-commit"
},
{
"match": "(new file:.*)$\\n?",
"name": "markup.inserted.git-commit"
},
{
"match": "(deleted:.*)$\\n?",
"name": "markup.deleted.git-commit"
}
]
}
]
},
{
"include": "#comment"
},
{
"begin": "(?=diff\\ \\-\\-git)",
"comment": "diff presented at the end of the commit message when using commit -v.",
"contentName": "source.diff",
"end": "\\z",
"name": "meta.embedded.diff.git-commit",
"patterns": [
{
"include": "source.diff"
}
]
}
]
}
}
}

View File

@@ -0,0 +1,36 @@
{
"information_for_contributors": [
"This file has been converted from https://github.com/textmate/git.tmbundle/blob/master/Syntaxes/Git%20Rebase%20Message.tmLanguage",
"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/textmate/git.tmbundle/commit/d1db42c2d71948662098183a6df519fb53a7a15b",
"name": "Git Rebase Message",
"scopeName": "text.git-rebase",
"patterns": [
{
"captures": {
"1": {
"name": "punctuation.definition.comment.git-rebase"
}
},
"match": "^\\s*(#).*$\\n?",
"name": "comment.line.number-sign.git-rebase"
},
{
"captures": {
"1": {
"name": "support.function.git-rebase"
},
"2": {
"name": "constant.sha.git-rebase"
},
"3": {
"name": "meta.commit-message.git-rebase"
}
},
"match": "^\\s*(pick|p|reword|r|edit|e|squash|s|fixup|f|exec|x|drop|d)\\s+([0-9a-f]+)\\s+(.*)$",
"name": "meta.commit-command.git-rebase"
}
]
}

View File

@@ -0,0 +1,13 @@
This is the summary line. It can't be too long.
After I can write a much more detailed description without quite the same restrictions on length.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
# deleted: README.md
# modified: index.less
# new file: spec/COMMIT_EDITMSG
#

View File

@@ -0,0 +1,7 @@
diff --git a/helloworld.txt b/helloworld.txt
index e4f37c4..557db03 100644
--- a/helloworld.txt
+++ b/helloworld.txt
@@ -1 +1 @@
-Hello world
+Hello World

View File

@@ -0,0 +1,15 @@
pick 1fc6c95 Patch A
squash fa39187 Something to add to patch A
pick 7b36971 Something to move before patch B
pick 6b2481b Patch B
fixup c619268 A fix for Patch B
edit dd1475d Something I want to split
reword 4ca2acc i cant' typ goods
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell

View File

@@ -0,0 +1,255 @@
[
{
"c": "This is the summary line. It can't be too long.",
"t": "text.git-commit meta.scope.message.git-commit meta.scope.subject.git-commit",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "After I can write a much more detailed description without quite the same restrictions on length.",
"t": "text.git-commit meta.scope.message.git-commit",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " Please enter the commit message for your changes. Lines starting",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " with '#' will be ignored, and an empty message aborts the commit.",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " On branch master",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " Your branch is up-to-date with 'origin/master'.",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " Changes to be committed:",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "\t",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "deleted: README.md",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit markup.deleted.git-commit",
"r": {
"dark_plus": "markup.deleted: #CE9178",
"light_plus": "markup.deleted: #A31515",
"dark_vs": "markup.deleted: #CE9178",
"light_vs": "markup.deleted: #A31515",
"hc_black": "markup.deleted: #CE9178"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "\t",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "modified: index.less",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit markup.changed.git-commit",
"r": {
"dark_plus": "markup.changed: #569CD6",
"light_plus": "markup.changed: #0451A5",
"dark_vs": "markup.changed: #569CD6",
"light_vs": "markup.changed: #0451A5",
"hc_black": "markup.changed: #569CD6"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "\t",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "new file: spec/COMMIT_EDITMSG",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit markup.inserted.git-commit",
"r": {
"dark_plus": "markup.inserted: #B5CEA8",
"light_plus": "markup.inserted: #09885A",
"dark_vs": "markup.inserted: #B5CEA8",
"light_vs": "markup.inserted: #09885A",
"hc_black": "markup.inserted: #B5CEA8"
}
},
{
"c": "#",
"t": "text.git-commit meta.scope.metadata.git-commit comment.line.number-sign.git-commit punctuation.definition.comment.git-commit",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
}
]

View File

@@ -0,0 +1,167 @@
[
{
"c": "diff --git a/helloworld.txt b/helloworld.txt",
"t": "source.diff meta.diff.header.git",
"r": {
"dark_plus": "meta.diff.header: #569CD6",
"light_plus": "meta.diff.header: #000080",
"dark_vs": "meta.diff.header: #569CD6",
"light_vs": "meta.diff.header: #000080",
"hc_black": "meta.diff.header: #000080"
}
},
{
"c": "index e4f37c4..557db03 100644",
"t": "source.diff meta.diff.index.git",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "---",
"t": "source.diff meta.diff.header.from-file punctuation.definition.from-file.diff",
"r": {
"dark_plus": "meta.diff.header: #569CD6",
"light_plus": "meta.diff.header: #000080",
"dark_vs": "meta.diff.header: #569CD6",
"light_vs": "meta.diff.header: #000080",
"hc_black": "meta.diff.header: #000080"
}
},
{
"c": " a/helloworld.txt",
"t": "source.diff meta.diff.header.from-file",
"r": {
"dark_plus": "meta.diff.header: #569CD6",
"light_plus": "meta.diff.header: #000080",
"dark_vs": "meta.diff.header: #569CD6",
"light_vs": "meta.diff.header: #000080",
"hc_black": "meta.diff.header: #000080"
}
},
{
"c": "+++",
"t": "source.diff meta.diff.header.to-file punctuation.definition.to-file.diff",
"r": {
"dark_plus": "meta.diff.header: #569CD6",
"light_plus": "meta.diff.header: #000080",
"dark_vs": "meta.diff.header: #569CD6",
"light_vs": "meta.diff.header: #000080",
"hc_black": "meta.diff.header: #000080"
}
},
{
"c": " b/helloworld.txt",
"t": "source.diff meta.diff.header.to-file",
"r": {
"dark_plus": "meta.diff.header: #569CD6",
"light_plus": "meta.diff.header: #000080",
"dark_vs": "meta.diff.header: #569CD6",
"light_vs": "meta.diff.header: #000080",
"hc_black": "meta.diff.header: #000080"
}
},
{
"c": "@@",
"t": "source.diff meta.diff.range.unified punctuation.definition.range.diff",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": " ",
"t": "source.diff meta.diff.range.unified",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "-1 +1",
"t": "source.diff meta.diff.range.unified meta.toc-list.line-number.diff",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": " ",
"t": "source.diff meta.diff.range.unified",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "@@",
"t": "source.diff meta.diff.range.unified punctuation.definition.range.diff",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "-",
"t": "source.diff markup.deleted.diff punctuation.definition.deleted.diff",
"r": {
"dark_plus": "markup.deleted: #CE9178",
"light_plus": "markup.deleted: #A31515",
"dark_vs": "markup.deleted: #CE9178",
"light_vs": "markup.deleted: #A31515",
"hc_black": "markup.deleted: #CE9178"
}
},
{
"c": "Hello world",
"t": "source.diff markup.deleted.diff",
"r": {
"dark_plus": "markup.deleted: #CE9178",
"light_plus": "markup.deleted: #A31515",
"dark_vs": "markup.deleted: #CE9178",
"light_vs": "markup.deleted: #A31515",
"hc_black": "markup.deleted: #CE9178"
}
},
{
"c": "+",
"t": "source.diff markup.inserted.diff punctuation.definition.inserted.diff",
"r": {
"dark_plus": "markup.inserted: #B5CEA8",
"light_plus": "markup.inserted: #09885A",
"dark_vs": "markup.inserted: #B5CEA8",
"light_vs": "markup.inserted: #09885A",
"hc_black": "markup.inserted: #B5CEA8"
}
},
{
"c": "Hello World",
"t": "source.diff markup.inserted.diff",
"r": {
"dark_plus": "markup.inserted: #B5CEA8",
"light_plus": "markup.inserted: #09885A",
"dark_vs": "markup.inserted: #B5CEA8",
"light_vs": "markup.inserted: #09885A",
"hc_black": "markup.inserted: #B5CEA8"
}
}
]

View File

@@ -0,0 +1,541 @@
[
{
"c": "pick",
"t": "text.git-rebase meta.commit-command.git-rebase support.function.git-rebase",
"r": {
"dark_plus": "support.function.git-rebase: #9CDCFE",
"light_plus": "support.function.git-rebase: #0451A5",
"dark_vs": "support.function.git-rebase: #9CDCFE",
"light_vs": "support.function.git-rebase: #0451A5",
"hc_black": "support.function.git-rebase: #D4D4D4"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "1fc6c95",
"t": "text.git-rebase meta.commit-command.git-rebase constant.sha.git-rebase",
"r": {
"dark_plus": "constant.sha.git-rebase: #B5CEA8",
"light_plus": "constant.sha.git-rebase: #09885A",
"dark_vs": "constant.sha.git-rebase: #B5CEA8",
"light_vs": "constant.sha.git-rebase: #09885A",
"hc_black": "constant.sha.git-rebase: #B5CEA8"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "Patch A",
"t": "text.git-rebase meta.commit-command.git-rebase meta.commit-message.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "squash",
"t": "text.git-rebase meta.commit-command.git-rebase support.function.git-rebase",
"r": {
"dark_plus": "support.function.git-rebase: #9CDCFE",
"light_plus": "support.function.git-rebase: #0451A5",
"dark_vs": "support.function.git-rebase: #9CDCFE",
"light_vs": "support.function.git-rebase: #0451A5",
"hc_black": "support.function.git-rebase: #D4D4D4"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "fa39187",
"t": "text.git-rebase meta.commit-command.git-rebase constant.sha.git-rebase",
"r": {
"dark_plus": "constant.sha.git-rebase: #B5CEA8",
"light_plus": "constant.sha.git-rebase: #09885A",
"dark_vs": "constant.sha.git-rebase: #B5CEA8",
"light_vs": "constant.sha.git-rebase: #09885A",
"hc_black": "constant.sha.git-rebase: #B5CEA8"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "Something to add to patch A",
"t": "text.git-rebase meta.commit-command.git-rebase meta.commit-message.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "pick",
"t": "text.git-rebase meta.commit-command.git-rebase support.function.git-rebase",
"r": {
"dark_plus": "support.function.git-rebase: #9CDCFE",
"light_plus": "support.function.git-rebase: #0451A5",
"dark_vs": "support.function.git-rebase: #9CDCFE",
"light_vs": "support.function.git-rebase: #0451A5",
"hc_black": "support.function.git-rebase: #D4D4D4"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "7b36971",
"t": "text.git-rebase meta.commit-command.git-rebase constant.sha.git-rebase",
"r": {
"dark_plus": "constant.sha.git-rebase: #B5CEA8",
"light_plus": "constant.sha.git-rebase: #09885A",
"dark_vs": "constant.sha.git-rebase: #B5CEA8",
"light_vs": "constant.sha.git-rebase: #09885A",
"hc_black": "constant.sha.git-rebase: #B5CEA8"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "Something to move before patch B",
"t": "text.git-rebase meta.commit-command.git-rebase meta.commit-message.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "pick",
"t": "text.git-rebase meta.commit-command.git-rebase support.function.git-rebase",
"r": {
"dark_plus": "support.function.git-rebase: #9CDCFE",
"light_plus": "support.function.git-rebase: #0451A5",
"dark_vs": "support.function.git-rebase: #9CDCFE",
"light_vs": "support.function.git-rebase: #0451A5",
"hc_black": "support.function.git-rebase: #D4D4D4"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "6b2481b",
"t": "text.git-rebase meta.commit-command.git-rebase constant.sha.git-rebase",
"r": {
"dark_plus": "constant.sha.git-rebase: #B5CEA8",
"light_plus": "constant.sha.git-rebase: #09885A",
"dark_vs": "constant.sha.git-rebase: #B5CEA8",
"light_vs": "constant.sha.git-rebase: #09885A",
"hc_black": "constant.sha.git-rebase: #B5CEA8"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "Patch B",
"t": "text.git-rebase meta.commit-command.git-rebase meta.commit-message.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "fixup",
"t": "text.git-rebase meta.commit-command.git-rebase support.function.git-rebase",
"r": {
"dark_plus": "support.function.git-rebase: #9CDCFE",
"light_plus": "support.function.git-rebase: #0451A5",
"dark_vs": "support.function.git-rebase: #9CDCFE",
"light_vs": "support.function.git-rebase: #0451A5",
"hc_black": "support.function.git-rebase: #D4D4D4"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "c619268",
"t": "text.git-rebase meta.commit-command.git-rebase constant.sha.git-rebase",
"r": {
"dark_plus": "constant.sha.git-rebase: #B5CEA8",
"light_plus": "constant.sha.git-rebase: #09885A",
"dark_vs": "constant.sha.git-rebase: #B5CEA8",
"light_vs": "constant.sha.git-rebase: #09885A",
"hc_black": "constant.sha.git-rebase: #B5CEA8"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "A fix for Patch B",
"t": "text.git-rebase meta.commit-command.git-rebase meta.commit-message.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "edit",
"t": "text.git-rebase meta.commit-command.git-rebase support.function.git-rebase",
"r": {
"dark_plus": "support.function.git-rebase: #9CDCFE",
"light_plus": "support.function.git-rebase: #0451A5",
"dark_vs": "support.function.git-rebase: #9CDCFE",
"light_vs": "support.function.git-rebase: #0451A5",
"hc_black": "support.function.git-rebase: #D4D4D4"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "dd1475d",
"t": "text.git-rebase meta.commit-command.git-rebase constant.sha.git-rebase",
"r": {
"dark_plus": "constant.sha.git-rebase: #B5CEA8",
"light_plus": "constant.sha.git-rebase: #09885A",
"dark_vs": "constant.sha.git-rebase: #B5CEA8",
"light_vs": "constant.sha.git-rebase: #09885A",
"hc_black": "constant.sha.git-rebase: #B5CEA8"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "Something I want to split",
"t": "text.git-rebase meta.commit-command.git-rebase meta.commit-message.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "reword",
"t": "text.git-rebase meta.commit-command.git-rebase support.function.git-rebase",
"r": {
"dark_plus": "support.function.git-rebase: #9CDCFE",
"light_plus": "support.function.git-rebase: #0451A5",
"dark_vs": "support.function.git-rebase: #9CDCFE",
"light_vs": "support.function.git-rebase: #0451A5",
"hc_black": "support.function.git-rebase: #D4D4D4"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "4ca2acc",
"t": "text.git-rebase meta.commit-command.git-rebase constant.sha.git-rebase",
"r": {
"dark_plus": "constant.sha.git-rebase: #B5CEA8",
"light_plus": "constant.sha.git-rebase: #09885A",
"dark_vs": "constant.sha.git-rebase: #B5CEA8",
"light_vs": "constant.sha.git-rebase: #09885A",
"hc_black": "constant.sha.git-rebase: #B5CEA8"
}
},
{
"c": " ",
"t": "text.git-rebase meta.commit-command.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "i cant' typ goods",
"t": "text.git-rebase meta.commit-command.git-rebase meta.commit-message.git-rebase",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "#",
"t": "text.git-rebase comment.line.number-sign.git-rebase punctuation.definition.comment.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " Commands:",
"t": "text.git-rebase comment.line.number-sign.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-rebase comment.line.number-sign.git-rebase punctuation.definition.comment.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " p, pick = use commit",
"t": "text.git-rebase comment.line.number-sign.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-rebase comment.line.number-sign.git-rebase punctuation.definition.comment.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " r, reword = use commit, but edit the commit message",
"t": "text.git-rebase comment.line.number-sign.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-rebase comment.line.number-sign.git-rebase punctuation.definition.comment.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " e, edit = use commit, but stop for amending",
"t": "text.git-rebase comment.line.number-sign.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-rebase comment.line.number-sign.git-rebase punctuation.definition.comment.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " s, squash = use commit, but meld into previous commit",
"t": "text.git-rebase comment.line.number-sign.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-rebase comment.line.number-sign.git-rebase punctuation.definition.comment.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " f, fixup = like \"squash\", but discard this commit's log message",
"t": "text.git-rebase comment.line.number-sign.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "#",
"t": "text.git-rebase comment.line.number-sign.git-rebase punctuation.definition.comment.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " x, exec = run command (the rest of the line) using shell",
"t": "text.git-rebase comment.line.number-sign.git-rebase",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
}
]

View File

@@ -10,7 +10,8 @@
"./node_modules/@types"
],
"strict": true,
"experimentalDecorators": true
"experimentalDecorators": true,
"noUnusedLocals": true
},
"include": [
"src/**/*"

View File

@@ -30,9 +30,13 @@
version "1.0.28"
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.0.28.tgz#016e387629b8817bed653fe32eab5d11279c8df6"
applicationinsights@0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-0.18.0.tgz#162ebb48a383408bc4de44db32b417307f45bbc1"
applicationinsights@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927"
dependencies:
diagnostic-channel "0.2.0"
diagnostic-channel-publishers "0.2.1"
zone.js "0.7.6"
balanced-match@^1.0.0:
version "1.0.0"
@@ -69,6 +73,16 @@ debug@2.6.8:
dependencies:
ms "2.0.0"
diagnostic-channel-publishers@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
diagnostic-channel@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
dependencies:
semver "^5.3.0"
diff@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
@@ -229,22 +243,25 @@ path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
semver@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
supports-color@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
dependencies:
has-flag "^1.0.0"
vscode-extension-telemetry@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz#2261bff986b6690a6f1f746a45ac5bd1f85d29e0"
vscode-extension-telemetry@0.0.15:
version "0.0.15"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.15.tgz#685c32f3b67e8fb85ba689c1d7f88ff90ff87856"
dependencies:
applicationinsights "0.18.0"
winreg "1.2.3"
applicationinsights "1.0.1"
vscode-nls@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"
vscode-nls@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
which@^1.3.0:
version "1.3.0"
@@ -252,10 +269,10 @@ which@^1.3.0:
dependencies:
isexe "^2.0.0"
winreg@1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.3.tgz#93ad116b2696da87d58f7265a8fcea5254a965d5"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
zone.js@0.7.6:
version "0.7.6"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"