提交 372a8f14 编写于 作者: A Akash Satheesan

Squashed 'lib/vscode/' changes from 631dbe250bc..cfa2e218100

cfa2e218100 Make sure we actually update the local resource roots (#122957)
206524cbf6f Merge pull request #122941 from microsoft/roblou/fix122701
0ce07162f07 Use the scoped context key service for notebook editor context keys Fix #122701
4fbe56e36b3 Merge pull request #122933 from microsoft/aeschli/122466
32a743d2af9 [JSON] Schema not found error on opening package.json. For #122279
0676e9a727e Fix port theme color typo (#122915)
85f8ebf1687 Fix context on LabelTunnelAction (#122856)
5913f53cab5 Block windows/iframes from preventing the unload (#122835) (#122869)
acd78c82ac6 Ensure that notebook cell URIs work (#122747)
4e185d89863 Merge pull request #122764 from microsoft/roblou/fix122407
7eb7814b56c Try to block webviews from cancelling unloads (#122758)
25092105030 Hardcode keybinding string to fix #122407
b084e6f4a73 Fix currently active indicator preventing editor switching (#122742)
bc2373aaa54 Merge pull request #122732 from microsoft/r156_tabs
d7a86f269a8 Disable tabs by default

git-subtree-dir: lib/vscode
git-subtree-split: cfa2e218100323074ac1948c885448fdf4de2a7f
上级 a631d196
......@@ -14,7 +14,7 @@
"dependencies": {
"jsonc-parser": "^3.0.0",
"request-light": "^0.4.0",
"vscode-json-languageservice": "^4.1.2",
"vscode-json-languageservice": "^4.1.3",
"vscode-languageserver": "^7.0.0",
"vscode-uri": "^3.0.2"
},
......
......@@ -105,10 +105,10 @@ request-light@^0.4.0:
https-proxy-agent "^2.2.4"
vscode-nls "^4.1.2"
vscode-json-languageservice@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-4.1.2.tgz#c3873f791e23488a8b373e02c85c232bd625e27a"
integrity sha512-atAz6m4UZCslB7yk03Qb3/MKn1E5l07063syAEUfKRcVKTVN3t1+/KDlGu1nVCRUFAgz5+18gKidQvO4PVPLdg==
vscode-json-languageservice@^4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-4.1.3.tgz#851564e529e649c13b844f10a80ea1d9095591a9"
integrity sha512-m/wUEt4zgCNUcvGmPr1ELo+ROQNKBgASpdOOAEpcSMwYE/6GzULZ1KfBhbX9or7qnC4E0oX+wwW+lrN3EUWCgw==
dependencies:
jsonc-parser "^3.0.0"
minimatch "^3.0.4"
......
......@@ -363,7 +363,7 @@
// "peekViewTitleDescription.foreground": "",
// Ports
"ports.iconRunningProcessforeground": "#80a2c2",
"ports.iconRunningProcessForeground": "#80a2c2",
// Editor: Diff
"diffEditor.insertedTextBackground": "#31958A55",
// "diffEditor.insertedTextBorder": "",
......
......@@ -16,7 +16,7 @@
"menu.foreground": "#CCCCCC",
"statusBarItem.remoteForeground": "#FFF",
"statusBarItem.remoteBackground": "#16825D",
"ports.iconRunningProcessforeground": "#369432",
"ports.iconRunningProcessForeground": "#369432",
"sideBarSectionHeader.background": "#0000",
"sideBarSectionHeader.border": "#ccc3",
"tab.lastPinnedBorder": "#ccc3"
......
......@@ -10,7 +10,7 @@
"selection.background": "#008000",
"editor.selectionBackground": "#FFFFFF",
"statusBarItem.remoteBackground": "#00000000",
"ports.iconRunningProcessforeground": "#FFFFFF"
"ports.iconRunningProcessForeground": "#FFFFFF"
},
"tokenColors": [
{
......
......@@ -18,7 +18,7 @@
"settings.numberInputBorder": "#CECECE",
"statusBarItem.remoteForeground": "#FFF",
"statusBarItem.remoteBackground": "#16825D",
"ports.iconRunningProcessforeground": "#369432",
"ports.iconRunningProcessForeground": "#369432",
"sideBarSectionHeader.background": "#0000",
"sideBarSectionHeader.border": "#61616130",
"tab.lastPinnedBorder": "#61616130",
......
......@@ -29,7 +29,7 @@
"statusBar.debuggingBackground": "#423523",
"statusBar.noFolderBackground": "#423523",
"statusBarItem.remoteBackground": "#6e583b",
"ports.iconRunningProcessforeground": "#369432",
"ports.iconRunningProcessForeground": "#369432",
"activityBar.background": "#221a0f",
"activityBar.foreground": "#d3af86",
"sideBar.background": "#362712",
......
......@@ -16,7 +16,7 @@
"editor.lineHighlightBackground": "#303030",
"editorLineNumber.activeForeground": "#949494",
"editor.wordHighlightBackground": "#4747a180",
"editor.wordHighlightStrongBackground": "#6767ce80",
"editor.wordHighlightStrongBackground": "#6767ce80",
"editorCursor.foreground": "#c07020",
"editorWhitespace.foreground": "#505037",
"editorIndentGuide.background": "#505037",
......@@ -33,7 +33,7 @@
"statusBar.noFolderBackground": "#505050",
"titleBar.activeBackground": "#505050",
"statusBarItem.remoteBackground": "#3655b5",
"ports.iconRunningProcessforeground": "#CCCCCC",
"ports.iconRunningProcessForeground": "#CCCCCC",
"activityBar.background": "#353535",
"activityBar.foreground": "#ffffff",
"activityBarBadge.background": "#3655b5",
......
......@@ -51,7 +51,7 @@
"statusBar.noFolderBackground": "#414339",
"statusBar.debuggingBackground": "#75715E",
"statusBarItem.remoteBackground": "#AC6218",
"ports.iconRunningProcessforeground": "#ccccc7",
"ports.iconRunningProcessForeground": "#ccccc7",
"activityBar.background": "#272822",
"activityBar.foreground": "#f8f8f2",
"sideBar.background": "#1e1f1c",
......
......@@ -506,7 +506,7 @@
"statusBar.noFolderBackground": "#705697",
"statusBar.debuggingBackground": "#705697",
"statusBarItem.remoteBackground": "#4e3c69",
"ports.iconRunningProcessforeground": "#749351",
"ports.iconRunningProcessForeground": "#749351",
"activityBar.background": "#EDEDF5",
"activityBar.foreground": "#705697",
"activityBarBadge.background": "#705697",
......
......@@ -10,7 +10,7 @@
"statusBar.background": "#700000",
"statusBar.noFolderBackground": "#700000",
"statusBarItem.remoteBackground": "#c33",
"ports.iconRunningProcessforeground": "#DB7E58",
"ports.iconRunningProcessForeground": "#DB7E58",
"editorGroupHeader.tabsBackground": "#330000",
"titleBar.activeBackground": "#770000",
"titleBar.inactiveBackground": "#772222",
......
......@@ -462,7 +462,7 @@
"statusBar.debuggingBackground": "#00212B",
"statusBar.noFolderBackground": "#00212B",
"statusBarItem.remoteBackground": "#2AA19899",
"ports.iconRunningProcessforeground": "#369432",
"ports.iconRunningProcessForeground": "#369432",
"statusBarItem.prominentBackground": "#003847",
"statusBarItem.prominentHoverBackground": "#003847",
// "statusBarItem.activeBackground": "",
......
......@@ -465,7 +465,7 @@
"statusBar.noFolderBackground": "#EEE8D5",
// "statusBar.foreground": "",
"statusBarItem.remoteBackground": "#AC9D57",
"ports.iconRunningProcessforeground": "#2AA19899",
"ports.iconRunningProcessForeground": "#2AA19899",
"statusBarItem.prominentBackground": "#DDD6C1",
"statusBarItem.prominentHoverBackground": "#DDD6C199",
// "statusBarItem.activeBackground": "",
......
......@@ -32,7 +32,7 @@
"titleBar.activeBackground": "#001126",
"statusBar.background": "#001126",
"statusBarItem.remoteBackground": "#0e639c",
"ports.iconRunningProcessforeground": "#bbdaff",
"ports.iconRunningProcessForeground": "#bbdaff",
"statusBar.noFolderBackground": "#001126",
"statusBar.debuggingBackground": "#001126",
"activityBar.background": "#001733",
......
......@@ -7,6 +7,7 @@ import * as assert from 'assert';
import * as glob from 'vs/base/common/glob';
import { sep } from 'vs/base/common/path';
import { isWindows } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
suite('Glob', () => {
......@@ -1019,4 +1020,9 @@ suite('Glob', () => {
assertNoGlobMatch(p, '/DNXConsoleApp/foo/Program.cs');
}
});
test('URI match', () => {
let p = 'scheme:/**/*.md';
assertGlobMatch(p, URI.file('super/duper/long/some/file.md').with({ scheme: 'scheme' }).toString());
});
});
......@@ -424,6 +424,15 @@ export class CodeWindow extends Disposable implements ICodeWindow {
this._win.webContents.on('render-process-gone', (event, details) => this.onWindowError(WindowError.CRASHED, details));
this._win.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this.onWindowError(WindowError.LOAD, errorDescription));
// Prevent windows/iframes from blocking the unload
// through DOM events. We have our own logic for
// unloading a window that should not be confused
// with the DOM way.
// (https://github.com/microsoft/vscode/issues/122736)
this._win.webContents.on('will-prevent-unload', event => {
event.preventDefault();
});
// Window close
this._win.on('closed', () => {
this._onDidClose.fire();
......
......@@ -3,21 +3,21 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Disposable } from 'vs/base/common/lifecycle';
import { isWindows } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IModeService } from 'vs/editor/common/services/modeService';
import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { CHANGE_CELL_LANGUAGE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { CellKind, CellStatusbarAlignment, INotebookCellStatusBarItem, INotebookCellStatusBarItemList, INotebookCellStatusBarItemProvider } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IModeService } from 'vs/editor/common/services/modeService';
import { CHANGE_CELL_LANGUAGE, EXECUTE_CELL_COMMAND_ID, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProvider {
readonly selector: NotebookSelector = {
......@@ -26,7 +26,6 @@ class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProv
constructor(
@INotebookService private readonly _notebookService: INotebookService,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
) { }
async provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise<INotebookCellStatusBarItemList | undefined> {
......@@ -38,19 +37,11 @@ class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProv
let text: string;
if (cell.cellKind === CellKind.Code) {
const keybinding = this._keybindingService.lookupKeybinding(EXECUTE_CELL_COMMAND_ID)?.getLabel();
if (!keybinding) {
return;
}
text = localize('notebook.cell.status.codeExecuteTip', "Press {0} to execute cell", keybinding);
text = isWindows ?
localize('notebook.cell.status.codeExecuteTipWin', "Press Ctrl+Alt+Enter to execute cell") :
localize('notebook.cell.status.codeExecuteTipNotWin', "Press Ctrl+Enter to execute cell");
} else {
const keybinding = this._keybindingService.lookupKeybinding(QUIT_EDIT_CELL_COMMAND_ID)?.getLabel();
if (!keybinding) {
return;
}
text = localize('notebook.cell.status.markdownExecuteTip', "Press {0} to stop editing", keybinding);
text = localize('notebook.cell.status.markdownExecuteTip', "Press Escape to stop editing");
}
const item = <INotebookCellStatusBarItem>{
......
......@@ -334,9 +334,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
this.scopedContextKeyService = contextKeyService.createScoped(this._overlayContainer);
this.instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService]));
this._register(instantiationService.createInstance(NotebookEditorContextKeys, this));
this._register(this.instantiationService.createInstance(NotebookEditorContextKeys, this));
this._kernelManger = instantiationService.createInstance(NotebookEditorKernelManager);
this._kernelManger = this.instantiationService.createInstance(NotebookEditorKernelManager);
this._register(notebookKernelService.onDidChangeNotebookKernelBinding(e => {
if (isEqual(e.notebook, this.viewModel?.uri)) {
this._loadKernelPreloads();
......
......@@ -37,9 +37,10 @@ import { Lazy } from 'vs/base/common/lazy';
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput';
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
import { ContributedEditorPriority, IEditorAssociationsRegistry, IEditorOverrideService, IEditorType, IEditorTypesHandler } from 'vs/workbench/services/editor/common/editorOverrideService';
import { EditorExtensions } from 'vs/workbench/common/editor';
import { ContributedEditorPriority, DiffEditorInputFactoryFunction, EditorInputFactoryFunction, IEditorAssociationsRegistry, IEditorOverrideService, IEditorType, IEditorTypesHandler } from 'vs/workbench/services/editor/common/editorOverrideService';
import { EditorExtensions, IEditorInput } from 'vs/workbench/common/editor';
import { IFileService } from 'vs/platform/files/common/files';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
export class NotebookProviderInfoStore extends Disposable {
......@@ -129,39 +130,52 @@ export class NotebookProviderInfoStore extends Disposable {
private _registerContributionPoint(notebookProviderInfo: NotebookProviderInfo): void {
for (const selector of notebookProviderInfo.selectors) {
const globPattern = (selector as INotebookExclusiveDocumentFilter).include || selector as glob.IRelativePattern | string;
const notebookEditorInfo = {
id: notebookProviderInfo.id,
label: notebookProviderInfo.displayName,
detail: notebookProviderInfo.providerDisplayName,
describes: (currentEditor: IEditorInput) => currentEditor instanceof NotebookEditorInput && currentEditor.viewType === notebookProviderInfo.id,
priority: notebookProviderInfo.exclusive ? ContributedEditorPriority.exclusive : notebookProviderInfo.priority,
};
const notebookEditorOptions = {
canHandleDiff: () => !!this._configurationService.getValue(NotebookTextDiffEditorPreview) && !this._accessibilityService.isScreenReaderOptimized(),
canSupportResource: (resource: URI) => resource.scheme === Schemas.untitled || resource.scheme === Schemas.vscodeNotebookCell || this._fileService.canHandleResource(resource)
};
const notebookEditorInputFactory: EditorInputFactoryFunction = (resource, options, group) => {
const data = CellUri.parse(resource);
let notebookUri: URI = resource;
let cellOptions: IResourceEditorInput | undefined;
if (data) {
notebookUri = data.notebook;
cellOptions = { resource: resource };
}
const notebookOptions = new NotebookEditorOptions({ ...options, cellOptions });
return { editor: NotebookEditorInput.create(this._instantiationService, notebookUri, notebookProviderInfo.id), options: notebookOptions };
};
const notebookEditorDiffFactory: DiffEditorInputFactoryFunction = (diffEditorInput: DiffEditorInput, options, group) => {
const modifiedInput = diffEditorInput.modifiedInput;
const originalInput = diffEditorInput.originalInput;
const notebookUri = modifiedInput.resource!;
const originalNotebookUri = originalInput.resource!;
return { editor: NotebookDiffEditorInput.create(this._instantiationService, notebookUri, modifiedInput.getName(), originalNotebookUri, originalInput.getName(), diffEditorInput.getName(), notebookProviderInfo.id) };
};
// Register the notebook editor
this._contributedEditorDisposables.add(this._editorOverrideService.registerContributionPoint(
globPattern,
{
id: notebookProviderInfo.id,
label: notebookProviderInfo.displayName,
detail: notebookProviderInfo.providerDisplayName,
describes: (currentEditor) => currentEditor instanceof NotebookEditorInput && currentEditor.viewType === notebookProviderInfo.id,
priority: notebookProviderInfo.exclusive ? ContributedEditorPriority.exclusive : notebookProviderInfo.priority,
},
{
canHandleDiff: () => !!this._configurationService.getValue(NotebookTextDiffEditorPreview) && !this._accessibilityService.isScreenReaderOptimized(),
canSupportResource: resource => resource.scheme === Schemas.untitled || resource.scheme === Schemas.vscodeNotebookCell || this._fileService.canHandleResource(resource)
},
(resource, options, group) => {
const data = CellUri.parse(resource);
let notebookUri: URI = resource;
let cellOptions: IResourceEditorInput | undefined;
if (data) {
notebookUri = data.notebook;
cellOptions = { resource: resource };
}
const notebookOptions = new NotebookEditorOptions({ ...options, cellOptions });
return { editor: NotebookEditorInput.create(this._instantiationService, notebookUri, notebookProviderInfo.id), options: notebookOptions };
},
(diffEditorInput, group) => {
const modifiedInput = diffEditorInput.modifiedInput;
const originalInput = diffEditorInput.originalInput;
const notebookUri = modifiedInput.resource!;
const originalNotebookUri = originalInput.resource!;
return { editor: NotebookDiffEditorInput.create(this._instantiationService, notebookUri, modifiedInput.getName(), originalNotebookUri, originalInput.getName(), diffEditorInput.getName(), notebookProviderInfo.id) };
}
notebookEditorInfo,
notebookEditorOptions,
notebookEditorInputFactory,
notebookEditorDiffFactory
));
// Then register the schema handler as exclusive for that notebook
this._contributedEditorDisposables.add(this._editorOverrideService.registerContributionPoint(
`${Schemas.vscodeNotebookCell}:/**/${globPattern}`,
{ ...notebookEditorInfo, priority: ContributedEditorPriority.exclusive },
notebookEditorOptions,
notebookEditorInputFactory,
notebookEditorDiffFactory
));
}
}
......
......@@ -965,10 +965,14 @@ namespace LabelTunnelAction {
export const LABEL = nls.localize('remote.tunnel.label', "Set Port Label");
export const COMMAND_ID_KEYWORD = 'label';
function isITunnelItem(item: any): item is ITunnelItem {
return item && item.tunnelType && item.remoteHost && item.source;
}
export function handler(): ICommandHandler {
return async (accessor, arg): Promise<{ port: number, label: string } | undefined> => {
const context = (arg !== undefined || arg instanceof TunnelItem) ? arg : accessor.get(IContextKeyService).getContextKeyValue(TunnelViewSelectionKeyName);
if (context instanceof TunnelItem) {
const context = isITunnelItem(arg) ? arg : accessor.get(IContextKeyService).getContextKeyValue<ITunnelItem | undefined>(TunnelViewSelectionKeyName);
if (context) {
return new Promise(resolve => {
const remoteExplorerService = accessor.get(IRemoteExplorerService);
const startingValue = context.name ? context.name : `${context.remotePort}`;
......@@ -1563,7 +1567,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelLocalAddressInline, ({
ContextKeyExpr.or(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), TunnelTypeContextKey.isEqualTo(TunnelType.Detected)))
}));
export const portWithRunningProcessForeground = registerColor('ports.iconRunningProcessforeground', {
export const portWithRunningProcessForeground = registerColor('ports.iconRunningProcessForeground', {
light: STATUS_BAR_HOST_NAME_BACKGROUND,
dark: STATUS_BAR_HOST_NAME_BACKGROUND,
hc: STATUS_BAR_HOST_NAME_BACKGROUND
......
......@@ -286,7 +286,7 @@ export const terminalConfiguration: IConfigurationNode = {
'terminal.integrated.tabs.enabled': {
description: localize('terminal.integrated.tabs.enabled', 'Controls whether terminal tabs display as a list to the side of the terminal. When this is disabled a dropdown will display instead.'),
type: 'boolean',
default: true,
default: false,
},
'terminal.integrated.tabs.hideCondition': {
description: localize('terminal.integrated.tabs.hideCondition', 'Controls whether the terminal tabs view will hide under certain conditions.'),
......
......@@ -372,8 +372,11 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
});
}
public set localResourcesRoot(resources: URI[]) {
/** no op */
public set localResourcesRoot(resources: readonly URI[]) {
this.content = {
...this.content,
options: { ...this.content.options, localResourceRoots: resources }
};
}
public set state(state: string | undefined) {
......
......@@ -226,8 +226,10 @@ export class EditorOverrideService extends Disposable implements IEditorOverride
const associationsFromSetting = this.getAssociationsForResource(resource);
// We only want built-in+ if no user defined setting is found, else we won't override
const possibleContributionPoints = contributionPoints.filter(contribPoint => priorityToRank(contribPoint.editorInfo.priority) >= priorityToRank(ContributedEditorPriority.builtin) && contribPoint.editorInfo.id !== DEFAULT_EDITOR_ASSOCIATION.id);
// If the user has a setting we use that, else choose the highest priority editor that is built-in+
const selectedViewType = associationsFromSetting[0]?.viewType || possibleContributionPoints[0]?.editorInfo.id;
// If the contribution is exclusive we use that, else use the user setting, else use the built-in+ contribution
const selectedViewType = possibleContributionPoints[0]?.editorInfo.priority === ContributedEditorPriority.exclusive ?
possibleContributionPoints[0]?.editorInfo.id :
associationsFromSetting[0]?.viewType || possibleContributionPoints[0]?.editorInfo.id;
let conflictingDefault = false;
if (associationsFromSetting.length === 0 && possibleContributionPoints.length > 1) {
......
......@@ -524,7 +524,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
id: DEFAULT_EDITOR_ASSOCIATION.id,
label: DEFAULT_EDITOR_ASSOCIATION.displayName,
detail: DEFAULT_EDITOR_ASSOCIATION.providerDisplayName,
describes: (currentEditor) => currentEditor.matches(this.activeEditor),
describes: (currentEditor) => this.fileEditorInputFactory.isFileEditorInput(currentEditor) && currentEditor.matches(this.activeEditor),
priority: ContributedEditorPriority.builtin
},
{},
......
......@@ -260,7 +260,7 @@ export function globMatchesResource(globPattern: string | glob.IRelativePattern,
return false;
}
const matchOnPath = typeof globPattern === 'string' && globPattern.indexOf(posix.sep) >= 0;
const target = matchOnPath ? resource.path : basename(resource);
const target = matchOnPath ? `${resource.scheme}:${resource.path}` : basename(resource);
return glob.match(globPattern, target.toLowerCase());
}
//#endregion
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册