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>;
|
|
}
|