提交 7aeeeecd 编写于 作者: I isidor

merge master

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
......@@ -38,7 +38,6 @@ var editorResources = [
'!out-build/vs/base/browser/ui/splitview/**/*',
'!out-build/vs/base/browser/ui/toolbar/**/*',
'!out-build/vs/base/browser/ui/octiconLabel/**/*',
'!out-build/vs/editor/contrib/defineKeybinding/**/*',
'!out-build/vs/workbench/**',
'!**/test/**'
];
......
......@@ -42,7 +42,7 @@ const nodeModules = ['electron', 'original-fs']
// Build
const builtInExtensions = [
{ name: 'ms-vscode.node-debug', version: '1.14.2' },
{ name: 'ms-vscode.node-debug', version: '1.14.4' },
{ name: 'ms-vscode.node-debug2', version: '1.14.0' }
];
......
"use strict";
var ts = require("./typescript/typescriptServices");
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var ts = require("typescript");
var lazy = require("lazy.js");
var event_stream_1 = require("event-stream");
var File = require("vinyl");
......@@ -69,7 +73,7 @@ function nls() {
return event_stream_1.duplex(input, output);
}
function isImportNode(node) {
return node.kind === 212 /* ImportDeclaration */ || node.kind === 211 /* ImportEqualsDeclaration */;
return node.kind === ts.SyntaxKind.ImportDeclaration || node.kind === ts.SyntaxKind.ImportEqualsDeclaration;
}
(function (nls_1) {
function fileFrom(file, contents, path) {
......@@ -111,27 +115,27 @@ function isImportNode(node) {
if (!ts.textSpanContainsTextSpan({ start: node.pos, length: node.end - node.pos }, textSpan)) {
return CollectStepResult.No;
}
return node.kind === 160 /* CallExpression */ ? CollectStepResult.YesAndRecurse : CollectStepResult.NoAndRecurse;
return node.kind === ts.SyntaxKind.CallExpression ? CollectStepResult.YesAndRecurse : CollectStepResult.NoAndRecurse;
}
function analyze(contents, options) {
if (options === void 0) { options = {}; }
var filename = 'file.ts';
var serviceHost = new SingleFileServiceHost(assign(clone(options), { noResolve: true }), filename, contents);
var service = ts.createLanguageService(serviceHost);
var sourceFile = service.getSourceFile(filename);
var sourceFile = ts.createSourceFile(filename, contents, ts.ScriptTarget.ES5, true);
// all imports
var imports = lazy(collect(sourceFile, function (n) { return isImportNode(n) ? CollectStepResult.YesAndRecurse : CollectStepResult.NoAndRecurse; }));
// import nls = require('vs/nls');
var importEqualsDeclarations = imports
.filter(function (n) { return n.kind === 211 /* ImportEqualsDeclaration */; })
.filter(function (n) { return n.kind === ts.SyntaxKind.ImportEqualsDeclaration; })
.map(function (n) { return n; })
.filter(function (d) { return d.moduleReference.kind === 222 /* ExternalModuleReference */; })
.filter(function (d) { return d.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference; })
.filter(function (d) { return d.moduleReference.expression.getText() === '\'vs/nls\''; });
// import ... from 'vs/nls';
var importDeclarations = imports
.filter(function (n) { return n.kind === 212 /* ImportDeclaration */; })
.filter(function (n) { return n.kind === ts.SyntaxKind.ImportDeclaration; })
.map(function (n) { return n; })
.filter(function (d) { return d.moduleSpecifier.kind === 8 /* StringLiteral */; })
.filter(function (d) { return d.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral; })
.filter(function (d) { return d.moduleSpecifier.getText() === '\'vs/nls\''; })
.filter(function (d) { return !!d.importClause && !!d.importClause.namedBindings; });
var nlsExpressions = importEqualsDeclarations
......@@ -143,7 +147,7 @@ function isImportNode(node) {
}); });
// `nls.localize(...)` calls
var nlsLocalizeCallExpressions = importDeclarations
.filter(function (d) { return d.importClause.namedBindings.kind === 214 /* NamespaceImport */; })
.filter(function (d) { return d.importClause.namedBindings.kind === ts.SyntaxKind.NamespaceImport; })
.map(function (d) { return d.importClause.namedBindings.name; })
.concat(importEqualsDeclarations.map(function (d) { return d.name; }))
.map(function (n) { return service.getReferencesAtPosition(filename, n.pos + 1); })
......@@ -153,10 +157,10 @@ function isImportNode(node) {
.map(function (a) { return lazy(a).last(); })
.filter(function (n) { return !!n; })
.map(function (n) { return n; })
.filter(function (n) { return n.expression.kind === 158 /* PropertyAccessExpression */ && n.expression.name.getText() === 'localize'; });
.filter(function (n) { return n.expression.kind === ts.SyntaxKind.PropertyAccessExpression && n.expression.name.getText() === 'localize'; });
// `localize` named imports
var allLocalizeImportDeclarations = importDeclarations
.filter(function (d) { return d.importClause.namedBindings.kind === 215 /* NamedImports */; })
.filter(function (d) { return d.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports; })
.map(function (d) { return d.importClause.namedBindings.elements; })
.flatten();
// `localize` read-only references
......
import * as ts from './typescript/typescriptServices';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as ts from 'typescript';
import * as lazy from 'lazy.js';
import { duplex, through } from 'event-stream';
import File = require('vinyl');
......@@ -171,7 +176,7 @@ module nls {
const filename = 'file.ts';
const serviceHost = new SingleFileServiceHost(assign(clone(options), { noResolve: true }), filename, contents);
const service = ts.createLanguageService(serviceHost);
const sourceFile = service.getSourceFile(filename);
const sourceFile = ts.createSourceFile(filename, contents, ts.ScriptTarget.ES5, true);
// all imports
const imports = lazy(collect(sourceFile, n => isImportNode(n) ? CollectStepResult.YesAndRecurse : CollectStepResult.NoAndRecurse));
......
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
[
{
"name": "typescript-legacy",
"version": "1.5",
"license": "Apache2",
"repositoryURL": "https://github.com/Microsoft/TypeScript",
// Reason: LICENSE file does not include Copyright statement
"licenseDetail": [
"Copyright (c) Microsoft Corporation. All rights reserved. ",
"",
"Apache License",
"",
"Version 2.0, January 2004",
"",
"http://www.apache.org/licenses/",
"",
"TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION",
"",
"1. Definitions.",
"",
"\"License\" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.",
"",
"\"Licensor\" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.",
"",
"\"Legal Entity\" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, \"control\" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.",
"",
"\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising permissions granted by this License.",
"",
"\"Source\" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.",
"",
"\"Object\" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.",
"",
"\"Work\" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).",
"",
"\"Derivative Works\" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.",
"",
"\"Contribution\" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, \"submitted\" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as \"Not a Contribution.\"",
"",
"\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.",
"",
"2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.",
"",
"3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.",
"",
"4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:",
"",
"You must give any other recipients of the Work or Derivative Works a copy of this License; and",
"",
"You must cause any modified files to carry prominent notices stating that You changed the files; and",
"",
"You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and",
"",
"If the Work includes a \"NOTICE\" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.",
"",
"5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.",
"",
"6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.",
"",
"7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.",
"",
"8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.",
"",
"9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.",
"",
"END OF TERMS AND CONDITIONS"
],
"isDev": true
}
]
\ No newline at end of file
此差异已折叠。
此差异已折叠。
......@@ -70,6 +70,7 @@ export interface ICommandHandler {
#include(vs/platform/markers/common/markers): IMarkerData
#include(vs/editor/browser/standalone/colorizer): IColorizerOptions, IColorizerElementOptions
#include(vs/base/common/scrollable): ScrollbarVisibility
#include(vs/platform/theme/common/themeService): ThemeColor
#includeAll(vs/editor/common/editorCommon;IMode=>languages.IMode;LanguageIdentifier=>languages.LanguageIdentifier;editorOptions.=>): ISelection, IScrollEvent
#includeAll(vs/editor/common/model/textModelEvents):
#includeAll(vs/editor/common/controller/cursorEvents):
......
......@@ -25,9 +25,22 @@ step "Install distro dependencies" \
step "Build minified" \
npm run gulp -- --max_old_space_size=4096 "vscode-linux-$ARCH-min"
step "Run smoke test" \
function configureEnvironment {
id -u testuser &>/dev/null || (useradd -m testuser; chpasswd <<< testuser:testpassword)
git config --global user.name "VS Code Agent"
git config --global user.email "monacotools@microsoft.com"
chown -R testuser $AGENT_BUILDDIRECTORY
}
function runTest {
pushd test/smoke
npm install
npm run compile
xvfb-run -a -s "-screen 0 1024x768x8" node src/main.js --latest "$AGENT_BUILDDIRECTORY/VSCode-linux-ia32/code-insiders"
popd
\ No newline at end of file
sudo -u testuser xvfb-run -a -s "-screen 0 1024x768x8" node src/main.js --latest "$AGENT_BUILDDIRECTORY/VSCode-linux-ia32/code-insiders"
popd
}
step "Configure environment" configureEnvironment
step "Run smoke test" runTest
......@@ -4,10 +4,9 @@ $ErrorActionPreference = 'Stop'
$env:HOME=$env:USERPROFILE
if (Test-Path env:AGENT_WORKFOLDER) {
$env:USERPROFILE="${env:AGENT_WORKFOLDER}\home"
$env:HOME="${env:USERPROFILE}"
$env:npm_config_cache="${env:USERPROFILE}\npm-cache"
New-Item -Path "$env:USERPROFILE" -Type directory -Force | out-null
$env:HOME="${env:AGENT_WORKFOLDER}\home"
$env:npm_config_cache="${env:HOME}\npm-cache"
New-Item -Path "$env:HOME" -Type directory -Force | out-null
New-Item -Path "$env:npm_config_cache" -Type directory -Force | out-null
}
......
[CustomMessages]
AddContextMenuFiles="Megnyits a kvetkezvel: %1" parancs hozzadsa a fjlok helyi menjhez a Windows Intzben
AddContextMenuFolders="Megnyits a kvetkezvel: %1" parancs hozzadsa a mappk helyi menjhez a Windows Intzben
AssociateWithFiles=%1 regisztrlsa szerkesztknt a tmogatott fjltpusokhoz
AddToPath=Hozzads a PATH-hoz (jraindts utn lesz elrhet)
RunAfter=%1 indtsa a telepts utn
Other=Egyb:
SourceFile=%1 forrsfjl
\ No newline at end of file
[CustomMessages]
AddContextMenuFiles=Windows Gezgini balam mensne "%1 le A" eylemini ekle
AddContextMenuFolders=Windows Gezgini dizin balam mensne "%1 le A" eylemini ekle
AssociateWithFiles=%1 uygulamasn desteklenen dosya trleri iin bir dzenleyici olarak kayt et
AddToPath=PATH'e ekle (yeniden balattktan sonra kullanlabilir)
RunAfter=Kurulumdan sonra %1 uygulamasn altr.
Other=Dier:
SourceFile=%1 Kaynak Dosyas
\ No newline at end of file
......@@ -6,7 +6,11 @@
import * as vscode from 'vscode';
import { expand, createSnippetsRegistry } from '@emmetio/expand-abbreviation';
import { getSyntax, getProfile, extractAbbreviation, isStyleSheet } from './util';
import { getSyntax, getProfile, extractAbbreviation, isStyleSheet, getNode } from './util';
import parseStylesheet from '@emmetio/css-parser';
import parse from '@emmetio/html-matcher';
import Node from '@emmetio/node';
import { DocumentStreamReader } from './bufferStream';
const field = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`;
const snippetCompletionsCache = new Map<string, vscode.CompletionItem[]>();
......@@ -22,7 +26,17 @@ export class EmmetCompletionItemProvider implements vscode.CompletionItemProvide
let completionItems: vscode.CompletionItem[] = [];
let syntax = getSyntax(document);
let currentWord = getCurrentWord(document, position);
let expandedAbbr = this.getExpandedAbbreviation(document, position);
let parseContent = isStyleSheet(syntax) ? parseStylesheet : parse;
let rootNode: Node = parseContent(new DocumentStreamReader(document));
let currentNode = getNode(rootNode, position);
// Inside <style> tag, trigger css abbreviations
if (!isStyleSheet(syntax) && currentNode && currentNode.name === 'style') {
syntax = 'css';
}
let expandedAbbr = this.getExpandedAbbreviation(document, position, syntax, currentNode);
if (!isStyleSheet(syntax)) {
if (expandedAbbr) {
......@@ -39,7 +53,7 @@ export class EmmetCompletionItemProvider implements vscode.CompletionItemProvide
return Promise.resolve(new vscode.CompletionList(completionItems, true));
}
getExpandedAbbreviation(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem {
getExpandedAbbreviation(document: vscode.TextDocument, position: vscode.Position, syntax: string, currentNode: Node): vscode.CompletionItem {
if (!vscode.workspace.getConfiguration('emmet')['showExpandedAbbreviation']) {
return;
}
......@@ -47,7 +61,10 @@ export class EmmetCompletionItemProvider implements vscode.CompletionItemProvide
if (!rangeToReplace || !wordToExpand) {
return;
}
let syntax = getSyntax(document);
if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position)) {
return;
}
let expandedWord = expand(wordToExpand, {
field: field,
syntax: syntax,
......@@ -114,6 +131,17 @@ function removeTabStops(expandedWord: string): string {
return expandedWord.replace(/\$\{\d+\}/g, '').replace(/\$\{\d+:([^\}]+)\}/g, '$1');
}
function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: string, position: vscode.Position): boolean {
if (!currentNode) {
return true;
}
if (isStyleSheet(syntax)) {
return currentNode.type !== 'rule';
}
return position.isAfter(currentNode.open.end);
}
......@@ -40,5 +40,5 @@
"config.ignoreLegacyWarning": "Ignores the legacy Git warning",
"config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository",
"config.defaultCloneDirectory": "The default location where to clone a git repository",
"config.enableSmartCommit": "Commit all changes when there are not staged changes."
}
\ No newline at end of file
"config.enableSmartCommit": "Commit all changes when there are no staged changes."
}
......@@ -78,6 +78,10 @@ export function activate(context: ExtensionContext) {
});
languages.setLanguageConfiguration('html', {
indentationRules: {
increaseIndentPattern: /<(?!\?|(?:area|base|br|col|frame|hr|html|img|input|link|meta|param)\b|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|<!--(?!.*-->)|\{[^}"']*$/,
decreaseIndentPattern: /^\s*(<\/(?!html)[-_\.A-Za-z0-9]+\b[^>]*>|-->|\})/
},
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,
onEnterRules: [
{
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
var updateGrammar = require('../../../build/npm/update-grammar');
function adaptInjectionScope(grammar) {
// we're using the HTML grammar from https://github.com/textmate/html.tmbundle which has moved away from source.js.embedded.html
let oldInjectionKey = "text.html.php - (meta.embedded | meta.tag), L:text.html.php meta.tag, L:source.js.embedded.html";
let newInjectionKey = "text.html.php - (meta.embedded | meta.tag), L:text.html.php meta.tag, L:text.html.php source.js";
var injections = grammar.injections;
var injection = injections[oldInjectionKey];
if (!injections) {
throw "Can not find PHP injection";
}
delete injections[oldInjectionKey];
injections[newInjectionKey] = injection;
}
updateGrammar.update('atom/language-php', 'grammars/php.cson', './syntaxes/php.tmLanguage.json', adaptInjectionScope);
......@@ -115,7 +115,7 @@
"scripts": {
"compile": "gulp compile-extension:php",
"watch": "gulp watch-extension:php",
"update-grammar": "node ../../build/npm/update-grammar.js atom/language-php grammars/php.cson ./syntaxes/php.tmLanguage.json"
"update-grammar": "node ./build/update-grammar.js"
},
"devDependencies": {
"@types/node": "^7.0.4"
......
<script>
...
<?php
foreach($actID AS $act) {
echo 'divNames.push(\'[nid='.$act.']\');';
}
?>
...
</script>
\ No newline at end of file
......@@ -467,7 +467,7 @@
"terminal.ansiMagenta": "#d33682",
"terminal.ansiCyan": "#2aa198",
"terminal.ansiWhite": "#eee8d5",
"terminal.ansiBrightBlack": "#002b36",
"terminal.ansiBrightBlack": "#586e75",
"terminal.ansiBrightRed": "#cb4b16",
"terminal.ansiBrightGreen": "#586e75",
"terminal.ansiBrightYellow": "#657b83",
......
......@@ -470,7 +470,7 @@
"terminal.ansiMagenta": "#d33682",
"terminal.ansiCyan": "#2aa198",
"terminal.ansiWhite": "#eee8d5",
"terminal.ansiBrightBlack": "#002b36",
"terminal.ansiBrightBlack": "#586e75",
"terminal.ansiBrightRed": "#cb4b16",
"terminal.ansiBrightGreen": "#586e75",
"terminal.ansiBrightYellow": "#657b83",
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit, window, QuickPickItem } from 'vscode';
import * as Proto from '../protocol';
import { ITypescriptServiceClient } from '../typescriptService';
export default class TypeScriptRefactorProvider implements CodeActionProvider {
private doRefactorCommandId: string;
private selectRefactorCommandId: string;
constructor(
private readonly client: ITypescriptServiceClient,
mode: string
) {
this.doRefactorCommandId = `_typescript.applyRefactoring.${mode}`;
this.selectRefactorCommandId = `_typescript.selectRefactoring.${mode}`;
commands.registerCommand(this.doRefactorCommandId, this.doRefactoring, this);
commands.registerCommand(this.selectRefactorCommandId, this.selectRefactoring, this);
}
public async provideCodeActions(
document: TextDocument,
range: Range,
_context: CodeActionContext,
token: CancellationToken
): Promise<Command[]> {
if (!this.client.apiVersion.has240Features()) {
return [];
}
const file = this.client.normalizePath(document.uri);
if (!file) {
return [];
}
const args: Proto.GetApplicableRefactorsRequestArgs = {
file: file,
startLine: range.start.line + 1,
startOffset: range.start.character + 1,
endLine: range.end.line + 1,
endOffset: range.end.character + 1
};
try {
const response = await this.client.execute('getApplicableRefactors', args, token);
if (!response || !response.body) {
return [];
}
const actions: Command[] = [];
for (const info of response.body) {
if (info.inlineable === false) {
actions.push({
title: info.description,
command: this.selectRefactorCommandId,
arguments: [file, info, range]
});
} else {
for (const action of info.actions) {
actions.push({
title: action.description,
command: this.doRefactorCommandId,
arguments: [file, info.name, action.name, range]
});
}
}
}
return actions;
} catch (err) {
return [];
}
}
private toWorkspaceEdit(edits: Proto.FileCodeEdits[]): WorkspaceEdit {
const workspaceEdit = new WorkspaceEdit();
for (const edit of edits) {
for (const textChange of edit.textChanges) {
workspaceEdit.replace(this.client.asUrl(edit.fileName),
new Range(
textChange.start.line - 1, textChange.start.offset - 1,
textChange.end.line - 1, textChange.end.offset - 1),
textChange.newText);
}
}
return workspaceEdit;
}
private async selectRefactoring(file: string, info: Proto.ApplicableRefactorInfo, range: Range): Promise<boolean> {
return window.showQuickPick(info.actions.map((action): QuickPickItem => ({
label: action.name,
description: action.description
}))).then(selected => {
if (!selected) {
return false;
}
return this.doRefactoring(file, info.name, selected.label, range);
});
}
private async doRefactoring(file: string, refactor: string, action: string, range: Range): Promise<boolean> {
const args: Proto.GetEditsForRefactorRequestArgs = {
file,
refactor,
action,
startLine: range.start.line + 1,
startOffset: range.start.character + 1,
endLine: range.end.line + 1,
endOffset: range.end.character + 1
};
const response = await this.client.execute('getEditsForRefactor', args);
if (!response || !response.body || !response.body.edits.length) {
return false;
}
const edit = this.toWorkspaceEdit(response.body.edits);
return workspace.applyEdit(edit);
}
}
\ No newline at end of file
......@@ -38,11 +38,11 @@ import BufferSyncSupport from './features/bufferSyncSupport';
import CompletionItemProvider from './features/completionItemProvider';
import WorkspaceSymbolProvider from './features/workspaceSymbolProvider';
import CodeActionProvider from './features/codeActionProvider';
import RefactorProvider from './features/refactorProvider';
import ReferenceCodeLensProvider from './features/referencesCodeLensProvider';
import { JsDocCompletionProvider, TryCompleteJsDocCommand } from './features/jsDocCompletionProvider';
import { DirectiveCommentCompletionProvider } from './features/directiveCommentCompletionProvider';
import TypeScriptTaskProviderManager from './features/taskProvider';
import ImplementationCodeLensProvider from './features/implementationsCodeLensProvider';
import * as ProjectStatus from './utils/projectStatus';
......@@ -167,6 +167,7 @@ export function activate(context: ExtensionContext): void {
const validateSetting = 'validate.enable';
class LanguageProvider {
private syntaxDiagnostics: ObjectMap<Diagnostic[]>;
private readonly currentDiagnostics: DiagnosticCollection;
private readonly bufferSyncSupport: BufferSyncSupport;
......@@ -263,7 +264,7 @@ class LanguageProvider {
this.disposables.push(languages.registerRenameProvider(selector, new RenameProvider(client)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new CodeActionProvider(client, this.description.id)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new RefactorProvider(client, this.description.id)));
this.registerVersionDependentProviders();
this.description.modeIds.forEach(modeId => {
......@@ -283,9 +284,10 @@ class LanguageProvider {
this.disposables.push(languages.setLanguageConfiguration(modeId, {
indentationRules: {
// ^(.*\*/)?\s*\}.*$
decreaseIndentPattern: /^(.*\*\/)?\s*\}.*$/,
decreaseIndentPattern: /^(.*\*\/)?\s*[\}|\]|\)].*$/,
// ^.*\{[^}"']*$
increaseIndentPattern: /^.*\{[^}"'`]*$/
increaseIndentPattern: /^.*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/,
indentNextLinePattern: /^\s*(for|while|if|else)\b(?!.*[;{}]\s*(\/\/.*|\/[*].*[*]\/\s*)?$)/
},
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
onEnterRules: [
......
......@@ -68,6 +68,9 @@ export class API {
public has234Features(): boolean {
return semver.gte(this._version, '2.3.4');
}
public has240Features(): boolean {
return semver.gte(this._version, '2.4.0');
}
}
export interface ITypescriptServiceClient {
......@@ -115,6 +118,8 @@ export interface ITypescriptServiceClient {
execute(command: 'getCodeFixes', args: Proto.CodeFixRequestArgs, token?: CancellationToken): Promise<Proto.GetCodeFixesResponse>;
execute(command: 'getSupportedCodeFixes', args: null, token?: CancellationToken): Promise<Proto.GetSupportedCodeFixesResponse>;
execute(command: 'docCommentTemplate', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.DocCommandTemplateResponse>;
execute(command: 'getApplicableRefactors', args: Proto.GetApplicableRefactorsRequestArgs, token?: CancellationToken): Promise<Proto.GetApplicableRefactorsResponse>;
execute(command: 'getEditsForRefactor', args: Proto.GetEditsForRefactorRequestArgs, token?: CancellationToken): Promise<Proto.GetEditsForRefactorResponse>;
// execute(command: 'compileOnSaveAffectedFileList', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise<Proto.CompileOnSaveAffectedFileListResponse>;
// execute(command: 'compileOnSaveEmitFile', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise<any>;
execute(command: string, args: any, expectedResult: boolean | CancellationToken, token?: CancellationToken): Promise<any>;
......
......@@ -32,7 +32,7 @@
"command.push": "推送",
"command.pushTo": "推送到...",
"command.sync": "同步",
"command.publish": "发布",
"command.publish": "发布分支",
"command.showOutput": "显示 GIT 输出",
"config.enabled": "是否已启用 GIT",
"config.path": "Git 可执行文件路径",
......
......@@ -3,4 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{}
\ No newline at end of file
{
"acceptCurrentChange": "采用当前更改",
"acceptIncomingChange": "采用传入的更改",
"acceptBothChanges": "保留双方更改",
"compareChanges": "比较变更"
}
\ No newline at end of file
......@@ -5,6 +5,8 @@
// Do not edit this file. It is machine generated.
{
"cursorNotInConflict": "编辑器光标不在合并冲突内",
"compareChangesTitle": "{0}:当前更改 ⟷ 传入的更改",
"cursorOnCommonAncestorsRange": "编辑器光标在共同来源块上,请将其移动至“当前”或“传入”区域中",
"cursorOnSplitterRange": "编辑器光标在合并冲突分割线上,请将其移动至“当前”或“传入”区域中",
"noConflicts": "没有在此文件中找到合并冲突",
"noOtherConflictsInThisFile": "此文件中没有其他合并冲突了"
......
......@@ -5,7 +5,15 @@
// Do not edit this file. It is machine generated.
{
"command.category": "合并冲突",
"command.accept.all-incoming": "全部采用传入版本",
"command.accept.all-both": "全部保留两者",
"command.accept.current": "采用当前内容",
"command.accept.incoming": "采用传入内容",
"command.accept.selection": "采用选中版本",
"command.accept.both": "保留两者",
"command.next": "下一个冲突",
"command.previous": "上一个冲突",
"command.compare": "比较当前冲突",
"config.title": "合并冲突",
"config.codeLensEnabled": "启用/禁用编辑器内合并冲突区域的 CodeLens",
"config.decoratorsEnabled": "启用/禁用编辑器内的合并冲突修饰器"
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"versionMismatch": "版本不匹配! 全局 tsc ({0}) != VS Code 的语言服务({1})。可能出现不一致的编译错误",
"versionMismatch": "正在使用 TypeScript ({1}) 实现的编辑器功能。TypeScript ({0}) 已经全局安装在你的电脑上。VS Code 中发生的错误可能会与 TCS 中不同",
"moreInformation": "详细信息",
"doNotCheckAgain": "不再检查",
"close": "关闭",
......
......@@ -6,7 +6,6 @@
{
"hintExclude": "若要启用项目范围内的 JavaScript/TypeScript 语言功能,请排除包含多个文件的文件夹,例如: {0}",
"hintExclude.generic": "若要启用项目范围内的 JavaScript/TypeScript 语言功能,请排除包含不需要处理的源文件的大型文件夹。",
"open": "配置排除",
"large.label": "配置排除",
"hintExclude.tooltip": "若要启用项目范围内的 JavaScript/TypeScript 语言功能,请排除包含不需要处理的源文件的大型文件夹。"
}
\ No newline at end of file
......@@ -5,6 +5,7 @@
// Do not edit this file. It is machine generated.
{
"installingPackages": "提取数据以实现更好的 TypeScript IntelliSense",
"typesInstallerInitializationFailed.title": "无法为 JavaScript 语言功能安装 typings 文件。请确认 NPM 已经安装或者在你的用户设置中配置“typescript.npm”",
"typesInstallerInitializationFailed.moreInformation": "详细信息",
"typesInstallerInitializationFailed.doNotCheckAgain": "不要再次检查",
"typesInstallerInitializationFailed.close": "关闭"
......
......@@ -13,11 +13,11 @@
"typescript.check.tscVersion": "检查全局安装的 TypeScript 编译器(例如 tsc )是否不同于使用的 TypeScript 语言服务。",
"typescript.tsserver.log": "将 TS 服务器的日志保存到一个文件。此日志可用于诊断 TS 服务器问题。日志可能包含你的项目中的文件路径、源代码和其他可能敏感的信息。",
"typescript.tsserver.trace": "对发送到 TS 服务器的消息启用跟踪。此跟踪信息可用于诊断 TS 服务器问题。 跟踪信息可能包含你的项目中的文件路径、源代码和其他可能敏感的信息。",
"typescript.tsserver.experimentalAutoBuild": "启用实验性自动生成。要求安装 1.9 dev 或 2.x tsserver 版本并在更改后重启 VS Code。",
"typescript.validate.enable": "启用/禁用 TypeScript 验证。",
"typescript.format.enable": "启用/禁用默认 TypeScript 格式化程序。",
"javascript.format.enable": "启用/禁用 JavaScript 格式化程序。",
"format.insertSpaceAfterCommaDelimiter": "定义逗号分隔符后面的空格处理。",
"format.insertSpaceAfterConstructor": "定义构造器关键字后的空格处理。要求 TypeScript >= 2.3.0。",
"format.insertSpaceAfterSemicolonInForStatements": "在 For 语句中,定义分号后面的空格处理。",
"format.insertSpaceBeforeAndAfterBinaryOperators": "定义二进制运算符后面的空格处理",
"format.insertSpaceAfterKeywordsInControlFlowStatements": "定义控制流语句中关键字后面的空格处理。",
......@@ -41,6 +41,8 @@
"typescript.selectTypeScriptVersion.title": "选择 TypeScript 版本",
"jsDocCompletion.enabled": "启用/禁用自动 JSDoc 注释",
"javascript.implicitProjectConfig.checkJs": "启用/禁用 JavaScript 文件的语义检查。现有的 jsconfig.json 或\n tsconfig.json 文件会覆盖此设置。要求 TypeScript >=2.3.1。",
"typescript.npm": "指定用于自动获取类型的 NPM 可执行文件的路径。要求 TypeScript >= 2.3.4。",
"typescript.check.npmIsInstalled": "检查是否安装了 NPM 以自动获取类型。",
"javascript.nameSuggestions": "启用/禁用在 JavaScript 建议列表中包含文件中的唯一名称。",
"typescript.tsc.autoDetect": "控制自动检测 tsc 任务是否打开。"
}
\ No newline at end of file
......@@ -13,6 +13,5 @@
"error.connection.unknown": "出现未知连接错误。您的 Internet 连接已断开,或者您连接的服务器已脱机。",
"stackTrace.format": "{0}: {1}",
"error.defaultMessage": "出现未知错误。有关详细信息,请参阅日志。",
"nodeExceptionMessage": "发生了系统错误({0})",
"error.moreErrors": "{0} 个(共 {1} 个错误)"
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{}
\ No newline at end of file
......@@ -12,6 +12,7 @@
"mDebug": "调试(&&D)",
"mWindow": "窗口",
"mHelp": "帮助(&&H)",
"mTask": "任务(&&T)",
"miNewWindow": "新建窗口(&&W)",
"mAbout": "关于 {0}",
"mServices": "服务",
......@@ -41,6 +42,7 @@
"miSelectIconTheme": "文件图标主题(&&I)",
"miPreferences": "首选项(&&P)",
"miReopenClosedEditor": "重新打开已关闭的编辑器(&&R)",
"miMore": "更多(&&M)...",
"miClearRecentOpen": "清除最近使用的文件(&&C)",
"miUndo": "撤消(&&U)",
"miRedo": "恢复(&&R)",
......@@ -55,6 +57,9 @@
"miShowEmmetCommands": "Emmet(&&M)...",
"miToggleLineComment": "切换行注释(&&T)",
"miToggleBlockComment": "切换块注释(&&B)",
"miMultiCursorAlt": "使用Alt+单击进行多光标功能",
"miMultiCursorCmd": "使用Cmd+单击进行多光标功能",
"miMultiCursorCtrl": "使用Ctrl+单击进行多光标功能",
"miInsertCursorAbove": "在上面添加光标(&&A)",
"miInsertCursorBelow": "在下面添加光标(&&D)",
"miInsertCursorAtEndOfEachLineSelected": "在行尾添加光标(&&U)",
......@@ -102,7 +107,7 @@
"miForward": "前进(&&F)",
"miNextEditor": "下一个编辑器(&&N)",
"miPreviousEditor": "上一个编辑器(&&P)",
"miNextEditorInGroup": "组中上一个使用过的编辑器(&&P)",
"miNextEditorInGroup": "组中下一个使用过的编辑器(&&N)",
"miPreviousEditorInGroup": "组中上一个使用过的编辑器(&&P)",
"miSwitchEditor": "切换编辑器(&&E)",
"miFocusFirstGroup": "第一组(&&F)",
......@@ -133,12 +138,14 @@
"miColumnBreakpoint": "列断点(&&O)",
"miFunctionBreakpoint": "函数断点(&&F)...",
"miNewBreakpoint": "新建断点(&&N)",
"miEnableAllBreakpoints": "启用所有断点",
"miDisableAllBreakpoints": "禁用所有断点(&&L)",
"miRemoveAllBreakpoints": "删除所有断点(&&R)",
"miInstallAdditionalDebuggers": "安装其他调试器(&&I)...",
"mMinimize": "最小化",
"mClose": "关闭",
"mZoom": "缩放",
"mBringToFront": "全部置于顶层",
"miSwitchWindow": "切换窗口(&&W)...",
"miToggleDevTools": "切换开发人员工具(&&T)",
"miAccessibilityOptions": "辅助功能选项(&&O)",
"miReportIssues": "报告问题(&&I)",
......@@ -153,12 +160,19 @@
"miLicense": "查看许可证(&&L)",
"miPrivacyStatement": "隐私声明(&&P)",
"miAbout": "关于(&&A)",
"miRunTask": "运行任务(&&R)...",
"miRestartTask": "重启任务(&&E)",
"miTerminateTask": "终止任务(&&T)",
"miBuildTask": "生成任务(&&B)",
"miTestTask": "测试任务(&&A)",
"miShowTaskLog": "显示任务日志(&&S)",
"accessibilityOptionsWindowTitle": "辅助功能选项",
"miRestartToUpdate": "重启以更新...",
"miCheckingForUpdates": "正在检查更新...",
"miDownloadUpdate": "下载可用更新",
"miDownloadingUpdate": "正在下载更新...",
"miInstallingUpdate": "正在安装更新...",
"miCheckForUpdates": "检查更新...",
"aboutDetail": "\n版本 {0}\n提交 {1}\n日期 {2}\nShell {3}\n渲染器 {4}\nNode {5}",
"okButton": "确定"
}
\ No newline at end of file
......@@ -13,9 +13,5 @@
"appStalled": "窗口不再响应",
"appStalledDetail": "可以重新打开或关闭窗,或者保持等待。",
"appCrashed": "窗口出现故障",
"appCrashedDetail": "我们对此引起的不便表示抱歉! 请重启该窗口从上次停止的位置继续。",
"newWindow": "新建窗口",
"newWindowDesc": "打开一个新窗口",
"recentFolders": "最近的文件夹",
"folderDesc": "{0} {1}"
"appCrashedDetail": "我们对此引起的不便表示抱歉! 请重启该窗口从上次停止的位置继续。"
}
\ No newline at end of file
......@@ -33,12 +33,15 @@
"wordWrapColumn": "在 \"editor.wordWrap\"\"wordWrapColumn\"\"bounded\" 时控制编辑器列的换行。",
"wrappingIndent": "控制折行的缩进。可以是“none”、“same”或“indent”。",
"mouseWheelScrollSensitivity": "要对鼠标滚轮滚动事件的 \"deltaX\"\"deltaY\" 使用的乘数 ",
"multiCursorModifier.ctrlCmd": "映射到“Control”(Windows 和 Linux)或“Command”(OSX)。",
"multiCursorModifier.alt": "映射到“Alt”(Windows 和 Linux)或“Option”(OSX)。",
"multiCursorModifier": "用鼠标添加多个光标时使用的修改键。“ctrlCmd”映射为“Control”(Windows 和 Linux)或“Command”(OSX)。“转到定义”和“打开链接”功能的鼠标手势将会相应调整,不与多光标修改键冲突。",
"quickSuggestions.strings": "在字符串内启用快速建议。",
"quickSuggestions.comments": "在注释内启用快速建议。",
"quickSuggestions.other": "在字符串和注释外启用快速建议。",
"quickSuggestions": "控制键入时是否应自动显示建议",
"quickSuggestionsDelay": "控制延迟多少毫秒后将显示快速建议",
"parameterHints": "启用参数提示",
"parameterHints": "启用在输入时显示含有参数文档和类型信息的小面板",
"autoClosingBrackets": "控制编辑器是否应该在左括号后自动插入右括号",
"formatOnType": "控制编辑器是否应在键入后自动设置行的格式",
"formatOnPaste": "控制编辑器是否应自动设置粘贴内容的格式。格式化程序必须可用并且能设置文档中某一范围的格式。",
......@@ -72,6 +75,10 @@
"trimAutoWhitespace": "删除尾随自动插入的空格",
"stablePeek": "即使在双击编辑器内容或按 Esc 键时,也要保持速览编辑器的打开状态。",
"dragAndDrop": "控制编辑器是否应该允许通过拖放移动所选项。",
"accessibilitySupport.auto": "编辑器将使用平台 API 以检测是否附加了屏幕阅读器。",
"accessibilitySupport.on": "编辑器将对屏幕阅读器的使用进行永久优化。",
"accessibilitySupport.off": "编辑器将不再对屏幕阅读器的使用进行优化。",
"accessibilitySupport": "控制编辑器是否应运行在对屏幕阅读器进行优化的模式。",
"sideBySide": "控制 Diff 编辑器以并排或内联形式显示差异",
"ignoreTrimWhitespace": "控制差异编辑器是否将对前导空格或尾随空格的更改显示为差异",
"renderIndicators": "控制差异编辑器是否为已添加/删除的更改显示 +/- 指示符号",
......
......@@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"accessibilityOffAriaLabel": "现在无法访问编辑器。按 Alt+F1 显示选项。",
"editorViewAccessibleLabel": "编辑器内容"
}
\ No newline at end of file
......@@ -14,6 +14,5 @@
"addSelectionToPreviousFindMatch": "将选择内容添加到上一查找匹配项",
"moveSelectionToNextFindMatch": "将上次选择移动到下一个查找匹配项",
"moveSelectionToPreviousFindMatch": "将上个选择内容移动到上一查找匹配项",
"selectAllOccurencesOfFindMatch": "选择所有找到的查找匹配项",
"changeAll.label": "更改所有匹配项"
}
\ No newline at end of file
......@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"hint11": "在第 {0} 行作出1 次格式编辑",
"hint11": "在第 {0} 行进行了 1 次格式编辑",
"hintn1": "在第 {1} 行进行了 {0} 次格式编辑",
"hint1n": "第 {0} 行到第 {1} 行间进行了 1 次格式编辑",
"hintnn": "Made {0} formatting edits between lines {1} and {2}",
"formatDocument.label": "Format Document",
"hintnn": "第 {1} 行到第 {2} 行间进行了 {0} 次格式编辑",
"formatDocument.label": "格式化文件",
"formatSelection.label": "格式化选定代码"
}
\ No newline at end of file
......@@ -5,8 +5,8 @@
// Do not edit this file. It is machine generated.
{
"aria.oneReference": "在文件 {0} 的 {1} 行 {2} 列的符号",
"aria.fileReferences.1": "{0} 中有 1 个符号",
"aria.fileReferences.N": "{1} 中有 {0} 个符号",
"aria.fileReferences.1": "{0} 中有 1 个符号,完整路径:{1}",
"aria.fileReferences.N": "{1} 中有 {0} 个符号,完整路径:{2}",
"aria.result.0": "未找到结果",
"aria.result.1": "在 {0} 中找到 1 个符号",
"aria.result.n1": "在 {1} 中找到 {0} 个符号",
......
......@@ -21,6 +21,8 @@
"menus.scmTitle": "源代码管理标题菜单",
"menus.resourceGroupContext": "源代码管理资源组上下文菜单",
"menus.resourceStateContext": "源代码管理资源状态上下文菜单",
"view.viewTitle": "提供的视图的标题菜单",
"view.itemContext": "提供的视图中的项目的上下文菜单",
"nonempty": "应为非空值。",
"opticon": "可以省略属性“图标”或者它必须是一个字符串或类似“{dark, light}”的文本",
"requireStringOrObject": "属性“{0}”为必需且其类型必须为“字符串”或“对象”",
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册