mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
parent
048752c031
commit
f2bcf4c272
|
@ -48,7 +48,7 @@ class GitHubGistProfileContentHandler implements vscode.ProfileContentHandler {
|
|||
}
|
||||
}
|
||||
|
||||
async saveProfile(name: string, content: string): Promise<vscode.Uri | null> {
|
||||
async saveProfile(name: string, content: string): Promise<{ readonly id: string; readonly link: vscode.Uri } | null> {
|
||||
const octokit = await this.getOctokit();
|
||||
const result = await octokit.gists.create({
|
||||
public: false,
|
||||
|
@ -58,7 +58,11 @@ class GitHubGistProfileContentHandler implements vscode.ProfileContentHandler {
|
|||
}
|
||||
}
|
||||
});
|
||||
return result.data.html_url ? vscode.Uri.parse(result.data.html_url) : null;
|
||||
if (result.data.id && result.data.html_url) {
|
||||
const link = vscode.Uri.parse(result.data.html_url);
|
||||
return { id: result.data.id, link };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private _public_octokit: Promise<Octokit> | undefined;
|
||||
|
@ -72,8 +76,10 @@ class GitHubGistProfileContentHandler implements vscode.ProfileContentHandler {
|
|||
return this._public_octokit;
|
||||
}
|
||||
|
||||
async readProfile(uri: vscode.Uri): Promise<string | null> {
|
||||
const gist_id = basename(uri.path);
|
||||
async readProfile(id: string): Promise<string | null>;
|
||||
async readProfile(uri: vscode.Uri): Promise<string | null>;
|
||||
async readProfile(arg: string | vscode.Uri): Promise<string | null> {
|
||||
const gist_id = typeof arg === 'string' ? arg : basename(arg.path);
|
||||
const octokit = await this.getPublicOctokit();
|
||||
try {
|
||||
const gist = await octokit.gists.get({ gist_id });
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Disposable, DisposableMap, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostContext, ExtHostProfileContentHandlersShape, MainContext, MainThreadProfileContentHandlersShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { IUserDataProfileImportExportService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
import { ISaveProfileResult, IUserDataProfileImportExportService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadProfileContentHandlers)
|
||||
export class MainThreadProfileContentHandlers extends Disposable implements MainThreadProfileContentHandlersShape {
|
||||
|
@ -31,7 +32,7 @@ export class MainThreadProfileContentHandlers extends Disposable implements Main
|
|||
extensionId,
|
||||
saveProfile: async (name: string, content: string, token: CancellationToken) => {
|
||||
const result = await this.proxy.$saveProfile(id, name, content, token);
|
||||
return result ? URI.revive(result) : null;
|
||||
return result ? revive<ISaveProfileResult>(result) : null;
|
||||
},
|
||||
readProfile: async (uri: URI, token: CancellationToken) => {
|
||||
return this.proxy.$readProfile(id, uri, token);
|
||||
|
|
|
@ -12,7 +12,7 @@ import { IMarkdownString } from 'vs/base/common/htmlContent';
|
|||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as performance from 'vs/base/common/performance';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents, UriDto } from 'vs/base/common/uri';
|
||||
import { RenderLineNumbersType, TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
|
@ -71,6 +71,7 @@ import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/qu
|
|||
import * as search from 'vs/workbench/services/search/common/search';
|
||||
import { EditSessionIdentityMatch } from 'vs/platform/workspace/common/editSessions';
|
||||
import { TerminalCommandMatchResult, TerminalQuickFixCommand, TerminalQuickFixOpener } from 'vscode';
|
||||
import { ISaveProfileResult } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
|
||||
export type TerminalQuickFix = TerminalQuickFixCommand | TerminalQuickFixOpener;
|
||||
|
||||
|
@ -1091,8 +1092,8 @@ export interface MainThreadProfileContentHandlersShape {
|
|||
}
|
||||
|
||||
export interface ExtHostProfileContentHandlersShape {
|
||||
$saveProfile(id: string, name: string, content: string, token: CancellationToken): Promise<UriComponents | null>;
|
||||
$readProfile(id: string, uri: UriComponents, token: CancellationToken): Promise<string | null>;
|
||||
$saveProfile(id: string, name: string, content: string, token: CancellationToken): Promise<UriDto<ISaveProfileResult> | null>;
|
||||
$readProfile(id: string, idOrUri: string | UriComponents, token: CancellationToken): Promise<string | null>;
|
||||
}
|
||||
|
||||
export interface ITextSearchComplete {
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ISaveProfileResult } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
import type * as vscode from 'vscode';
|
||||
import { ExtHostProfileContentHandlersShape, IMainContext, MainContext, MainThreadProfileContentHandlersShape } from './extHost.protocol';
|
||||
|
||||
|
@ -43,7 +45,7 @@ export class ExtHostProfileContentHandlers implements ExtHostProfileContentHandl
|
|||
});
|
||||
}
|
||||
|
||||
async $saveProfile(id: string, name: string, content: string, token: CancellationToken): Promise<UriComponents | null> {
|
||||
async $saveProfile(id: string, name: string, content: string, token: CancellationToken): Promise<ISaveProfileResult | null> {
|
||||
const handler = this.handlers.get(id);
|
||||
if (!handler) {
|
||||
throw new Error(`Unknown handler with id: ${id}`);
|
||||
|
@ -52,12 +54,12 @@ export class ExtHostProfileContentHandlers implements ExtHostProfileContentHandl
|
|||
return handler.saveProfile(name, content, token);
|
||||
}
|
||||
|
||||
async $readProfile(id: string, uri: UriComponents, token: CancellationToken): Promise<string | null> {
|
||||
async $readProfile(id: string, idOrUri: string | UriComponents, token: CancellationToken): Promise<string | null> {
|
||||
const handler = this.handlers.get(id);
|
||||
if (!handler) {
|
||||
throw new Error(`Unknown handler with id: ${id}`);
|
||||
}
|
||||
|
||||
return handler.readProfile(URI.revive(uri), token);
|
||||
return handler.readProfile(isString(idOrUri) ? idOrUri : URI.revive(idOrUri), token);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/
|
|||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IUserDataProfileImportExportService, PROFILE_FILTER, PROFILE_EXTENSION, IUserDataProfileContentHandler, IS_PROFILE_IMPORT_IN_PROGRESS_CONTEXT, PROFILES_TTILE, defaultUserDataProfileIcon, IUserDataProfileService, IProfileResourceTreeItem, IProfileResourceChildTreeItem, PROFILES_CATEGORY, IUserDataProfileManagementService, ProfileResourceType, IS_PROFILE_EXPORT_IN_PROGRESS_CONTEXT } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
import { IUserDataProfileImportExportService, PROFILE_FILTER, PROFILE_EXTENSION, IUserDataProfileContentHandler, IS_PROFILE_IMPORT_IN_PROGRESS_CONTEXT, PROFILES_TTILE, defaultUserDataProfileIcon, IUserDataProfileService, IProfileResourceTreeItem, IProfileResourceChildTreeItem, PROFILES_CATEGORY, IUserDataProfileManagementService, ProfileResourceType, IS_PROFILE_EXPORT_IN_PROGRESS_CONTEXT, ISaveProfileResult } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
|
@ -87,6 +87,7 @@ const EXPORT_PROFILE_PREVIEW_VIEW = 'workbench.views.profiles.export.preview';
|
|||
export class UserDataProfileImportExportService extends Disposable implements IUserDataProfileImportExportService, IURLHandler {
|
||||
|
||||
private static readonly PROFILE_URL_AUTHORITY_PREFIX = 'profile-';
|
||||
private static readonly PROFILE_URL_AUTHORITY = 'profile';
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
|
@ -116,6 +117,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
|
|||
@IRequestService private readonly requestService: IRequestService,
|
||||
@IURLService urlService: IURLService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
|
@ -139,7 +141,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
|
|||
}
|
||||
|
||||
private isProfileURL(uri: URI): boolean {
|
||||
return new RegExp(`^${UserDataProfileImportExportService.PROFILE_URL_AUTHORITY_PREFIX}`).test(uri.authority);
|
||||
return uri.authority === UserDataProfileImportExportService.PROFILE_URL_AUTHORITY || new RegExp(`^${UserDataProfileImportExportService.PROFILE_URL_AUTHORITY_PREFIX}`).test(uri.authority);
|
||||
}
|
||||
|
||||
async handleURL(uri: URI): Promise<boolean> {
|
||||
|
@ -322,14 +324,24 @@ export class UserDataProfileImportExportService extends Disposable implements IU
|
|||
location: ProgressLocation.Window,
|
||||
title: localize('profiles.exporting', "{0}: Exporting...", PROFILES_CATEGORY.value),
|
||||
}, async progress => {
|
||||
const saveResult = await this.saveProfileContent(profile.name, JSON.stringify(profile));
|
||||
if (saveResult) {
|
||||
const profileHandler = this.profileContentHandlers.get(saveResult.id);
|
||||
const buttons = profileHandler?.extensionId ? [localize('copy', "Copy Link"), localize('open', "Open in {0}", profileHandler?.name), localize('close', "Close")] : undefined;
|
||||
const id = await this.pickProfileContentHandler(profile.name);
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
const profileContentHandler = this.profileContentHandlers.get(id);
|
||||
if (!profileContentHandler) {
|
||||
return;
|
||||
}
|
||||
const saveResult = await profileContentHandler.saveProfile(profile.name, JSON.stringify(profile), CancellationToken.None);
|
||||
if (!saveResult) {
|
||||
return;
|
||||
}
|
||||
const message = localize('export success', "Profile '{0}' is exported successfully.", profile.name);
|
||||
if (profileContentHandler.extensionId) {
|
||||
const result = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
localize('export success', "Profile '{0}' is exported successfully.", profile.name),
|
||||
buttons,
|
||||
message,
|
||||
[localize('copy', "Copy Link"), localize('open', "Open in {0}", profileContentHandler.name), localize('close', "Close")],
|
||||
{ cancelId: 2 }
|
||||
);
|
||||
switch (result.choice) {
|
||||
|
@ -337,15 +349,17 @@ export class UserDataProfileImportExportService extends Disposable implements IU
|
|||
await this.clipboardService.writeText(
|
||||
URI.from({
|
||||
scheme: this.productService.urlProtocol,
|
||||
authority: `${UserDataProfileImportExportService.PROFILE_URL_AUTHORITY_PREFIX}${saveResult.id}`,
|
||||
path: `/${saveResult.resource.toString()}`
|
||||
authority: `${UserDataProfileImportExportService.PROFILE_URL_AUTHORITY}`,
|
||||
path: `/${id}/${saveResult.id}`
|
||||
}).toString());
|
||||
break;
|
||||
case 1:
|
||||
await this.openerService.open(saveResult.resource.toString());
|
||||
await this.openerService.open(saveResult.link.toString());
|
||||
break;
|
||||
|
||||
}
|
||||
} else {
|
||||
await this.dialogService.show(Severity.Info, message);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
|
@ -353,30 +367,24 @@ export class UserDataProfileImportExportService extends Disposable implements IU
|
|||
}
|
||||
}
|
||||
|
||||
private async saveProfileContent(name: string, content: string): Promise<{ resource: URI; id: string } | null> {
|
||||
const id = await this.pickProfileContentHandler(name);
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
const profileContentHandler = this.profileContentHandlers.get(id);
|
||||
if (!profileContentHandler) {
|
||||
return null;
|
||||
}
|
||||
const resource = await profileContentHandler.saveProfile(name, content, CancellationToken.None);
|
||||
return resource ? { resource, id } : null;
|
||||
}
|
||||
|
||||
private async resolveProfileContent(resource: URI): Promise<string | null> {
|
||||
if (await this.fileService.canHandleResource(resource)) {
|
||||
return this.fileUserDataProfileContentHandler.readProfile(resource, CancellationToken.None);
|
||||
}
|
||||
|
||||
if (this.isProfileURL(resource)) {
|
||||
const handlerId = resource.authority.substring(UserDataProfileImportExportService.PROFILE_URL_AUTHORITY_PREFIX.length);
|
||||
let handlerId: string, idOrUri: string | URI;
|
||||
if (resource.authority === UserDataProfileImportExportService.PROFILE_URL_AUTHORITY) {
|
||||
idOrUri = this.uriIdentityService.extUri.basename(resource);
|
||||
handlerId = this.uriIdentityService.extUri.basename(this.uriIdentityService.extUri.dirname(resource));
|
||||
} else {
|
||||
handlerId = resource.authority.substring(UserDataProfileImportExportService.PROFILE_URL_AUTHORITY_PREFIX.length);
|
||||
idOrUri = URI.parse(resource.path.substring(1));
|
||||
}
|
||||
await this.extensionService.activateByEvent(`onProfile:${handlerId}`);
|
||||
const profileContentHandler = this.profileContentHandlers.get(handlerId);
|
||||
if (profileContentHandler) {
|
||||
return profileContentHandler.readProfile(URI.parse(resource.path.substring(1)), CancellationToken.None);
|
||||
return profileContentHandler.readProfile(idOrUri, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,17 +607,17 @@ class FileUserDataProfileContentHandler implements IUserDataProfileContentHandle
|
|||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
) { }
|
||||
|
||||
async saveProfile(name: string, content: string, token: CancellationToken): Promise<URI | null> {
|
||||
const profileLocation = await this.fileDialogService.showSaveDialog({
|
||||
async saveProfile(name: string, content: string, token: CancellationToken): Promise<ISaveProfileResult | null> {
|
||||
const link = await this.fileDialogService.showSaveDialog({
|
||||
title: localize('export profile dialog', "Save Profile"),
|
||||
filters: PROFILE_FILTER,
|
||||
defaultUri: this.uriIdentityService.extUri.joinPath(await this.fileDialogService.defaultFilePath(), `${name}.${PROFILE_EXTENSION}`),
|
||||
});
|
||||
if (!profileLocation) {
|
||||
if (!link) {
|
||||
return null;
|
||||
}
|
||||
await this.textFileService.create([{ resource: profileLocation, value: content, options: { overwrite: true } }]);
|
||||
return profileLocation;
|
||||
await this.textFileService.create([{ resource: link, value: content, options: { overwrite: true } }]);
|
||||
return { link, id: link.toString() };
|
||||
}
|
||||
|
||||
async readProfile(uri: URI, token: CancellationToken): Promise<string | null> {
|
||||
|
|
|
@ -105,11 +105,16 @@ export interface IProfileResourceChildTreeItem extends ITreeItem {
|
|||
parent: IProfileResourceTreeItem;
|
||||
}
|
||||
|
||||
export interface ISaveProfileResult {
|
||||
readonly id: string;
|
||||
readonly link: URI;
|
||||
}
|
||||
|
||||
export interface IUserDataProfileContentHandler {
|
||||
readonly name: string;
|
||||
readonly extensionId?: string;
|
||||
saveProfile(name: string, content: string, token: CancellationToken): Promise<URI | null>;
|
||||
readProfile(uri: URI, token: CancellationToken): Promise<string | null>;
|
||||
saveProfile(name: string, content: string, token: CancellationToken): Promise<ISaveProfileResult | null>;
|
||||
readProfile(idOrUri: string | URI, token: CancellationToken): Promise<string | null>;
|
||||
}
|
||||
|
||||
export const defaultUserDataProfileIcon = registerIcon('defaultProfile-icon', Codicon.settings, localize('defaultProfileIcon', 'Icon for Default Profile.'));
|
||||
|
|
|
@ -7,8 +7,8 @@ declare module 'vscode' {
|
|||
|
||||
export interface ProfileContentHandler {
|
||||
readonly name: string;
|
||||
saveProfile(name: string, content: string, token: CancellationToken): Thenable<Uri | null>;
|
||||
readProfile(uri: Uri, token: CancellationToken): Thenable<string | null>;
|
||||
saveProfile(name: string, content: string, token: CancellationToken): Thenable<{ readonly id: string; readonly link: Uri } | null>;
|
||||
readProfile(idOrUri: string | Uri, token: CancellationToken): Thenable<string | null>;
|
||||
}
|
||||
|
||||
export namespace window {
|
||||
|
|
Loading…
Reference in a new issue