You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

244 lines
7.6 KiB

import type { ConfigurationChangeEvent } from 'vscode';
import { ConfigurationTarget, Disposable } from 'vscode';
import type { Container } from '../container';
import { CommitFormatter } from '../git/formatters/commitFormatter';
import { GitCommit, GitCommitIdentity } from '../git/models/commit';
import { GitFileChange, GitFileIndexStatus } from '../git/models/file';
import { PullRequest, PullRequestState } from '../git/models/pullRequest';
import { configuration } from '../system/configuration';
import { Logger } from '../system/logger';
import type { CustomConfigPath, IpcMessage } from './protocol';
import {
DidChangeConfigurationNotificationType,
DidGenerateConfigurationPreviewNotificationType,
GenerateConfigurationPreviewCommandType,
isCustomConfigKey,
onIpc,
UpdateConfigurationCommandType,
} from './protocol';
import type { WebviewController, WebviewProvider } from './webviewController';
import type { WebviewIds, WebviewViewIds } from './webviewsController';
export abstract class WebviewProviderWithConfigBase<State> implements WebviewProvider<State> {
private readonly _disposable: Disposable;
constructor(
readonly container: Container,
readonly id: `gitlens.${WebviewIds}` | `gitlens.views.${WebviewViewIds}`,
readonly host: WebviewController<State>,
) {
this._disposable = Disposable.from(
configuration.onDidChange(this.onConfigurationChanged, this),
configuration.onDidChangeAny(this.onAnyConfigurationChanged, this),
);
}
dispose() {
this._disposable.dispose();
}
onActiveChanged(active: boolean): void {
// Anytime the webview becomes active, make sure it has the most up-to-date config
if (active) {
void this.notifyDidChangeConfiguration();
}
}
onMessageReceived(e: IpcMessage): void {
if (e == null) return;
switch (e.method) {
case UpdateConfigurationCommandType.method:
Logger.debug(`Webview(${this.id}).onMessageReceived: method=${e.method}`);
onIpc(UpdateConfigurationCommandType, e, async params => {
const target =
params.scope === 'workspace' ? ConfigurationTarget.Workspace : ConfigurationTarget.Global;
let key: keyof typeof params.changes;
for (key in params.changes) {
let value = params.changes[key];
if (isCustomConfigKey(key)) {
const customSetting = this.customSettings.get(key);
if (customSetting != null) {
if (typeof value === 'boolean') {
await customSetting.update(value);
} else {
debugger;
}
}
continue;
}
const inspect = configuration.inspect(key)!;
if (value != null) {
if (params.scope === 'workspace') {
if (value === inspect.workspaceValue) continue;
} else {
if (value === inspect.globalValue && value !== inspect.defaultValue) continue;
if (value === inspect.defaultValue) {
value = undefined;
}
}
}
await configuration.update(key as any, value, target);
}
for (const key of params.removes) {
await configuration.update(key as any, undefined, target);
}
});
break;
case GenerateConfigurationPreviewCommandType.method:
Logger.debug(`Webview(${this.id}).onMessageReceived: method=${e.method}`);
onIpc(GenerateConfigurationPreviewCommandType, e, async params => {
switch (params.type) {
case 'commit':
case 'commit-uncommitted': {
const commit = new GitCommit(
this.container,
'~/code/eamodio/vscode-gitlens-demo',
'fe26af408293cba5b4bfd77306e1ac9ff7ccaef8',
new GitCommitIdentity('You', 'eamodio@gmail.com', new Date('2016-11-12T20:41:00.000Z')),
new GitCommitIdentity('You', 'eamodio@gmail.com', new Date('2020-11-01T06:57:21.000Z')),
params.type === 'commit-uncommitted' ? 'Uncommitted changes' : 'Supercharged',
['3ac1d3f51d7cf5f438cc69f25f6740536ad80fef'],
params.type === 'commit-uncommitted' ? 'Uncommitted changes' : 'Supercharged',
new GitFileChange(
'~/code/eamodio/vscode-gitlens-demo',
'code.ts',
GitFileIndexStatus.Modified,
),
undefined,
[],
);
let includePullRequest = false;
switch (params.key) {
case configuration.name('currentLine.format'):
includePullRequest = configuration.get('currentLine.pullRequests.enabled');
break;
case configuration.name('statusBar.format'):
includePullRequest = configuration.get('statusBar.pullRequests.enabled');
break;
}
let pr: PullRequest | undefined;
if (includePullRequest) {
pr = new PullRequest(
{ id: 'github', name: 'GitHub', domain: 'github.com', icon: 'github' },
{
name: 'Eric Amodio',
avatarUrl: 'https://avatars1.githubusercontent.com/u/641685?s=32&v=4',
url: 'https://github.com/eamodio',
},
'1',
'Supercharged',
'https://github.com/gitkraken/vscode-gitlens/pulls/1',
PullRequestState.Merged,
new Date('Sat, 12 Nov 2016 19:41:00 GMT'),
undefined,
new Date('Sat, 12 Nov 2016 20:41:00 GMT'),
);
}
let preview;
try {
preview = CommitFormatter.fromTemplate(params.format, commit, {
dateFormat: configuration.get('defaultDateFormat'),
pullRequestOrRemote: pr,
messageTruncateAtNewLine: true,
});
} catch {
preview = 'Invalid format';
}
await this.host.notify(
DidGenerateConfigurationPreviewNotificationType,
{ preview: preview },
e.completionId,
);
}
}
});
break;
}
}
private onAnyConfigurationChanged(e: ConfigurationChangeEvent) {
let notify = false;
for (const setting of this.customSettings.values()) {
if (e.affectsConfiguration(setting.name)) {
notify = true;
break;
}
}
if (!notify) return;
void this.notifyDidChangeConfiguration();
}
private onConfigurationChanged(_e: ConfigurationChangeEvent) {
void this.notifyDidChangeConfiguration();
}
private _customSettings: Map<CustomConfigPath, CustomSetting> | undefined;
private get customSettings() {
if (this._customSettings == null) {
this._customSettings = new Map<CustomConfigPath, CustomSetting>([
[
'rebaseEditor.enabled',
{
name: 'workbench.editorAssociations',
enabled: () => this.container.rebaseEditor.enabled,
update: this.container.rebaseEditor.setEnabled,
},
],
[
'currentLine.useUncommittedChangesFormat',
{
name: 'currentLine.useUncommittedChangesFormat',
enabled: () => configuration.get('currentLine.uncommittedChangesFormat') != null,
update: async enabled =>
configuration.updateEffective(
'currentLine.uncommittedChangesFormat',
// eslint-disable-next-line no-template-curly-in-string
enabled ? '✏️ ${ago}' : null,
),
},
],
]);
}
return this._customSettings;
}
protected getCustomSettings(): Record<string, boolean> {
const customSettings: Record<string, boolean> = Object.create(null);
for (const [key, setting] of this.customSettings) {
customSettings[key] = setting.enabled();
}
return customSettings;
}
private notifyDidChangeConfiguration() {
// Make sure to get the raw config, not from the container which has the modes mixed in
return this.host.notify(DidChangeConfigurationNotificationType, {
config: configuration.getAll(true),
customSettings: this.getCustomSettings(),
});
}
}
interface CustomSetting {
name: string;
enabled: () => boolean;
update: (enabled: boolean) => Promise<void>;
}