Browse Source

Adds real-time preview of format strings

main
Eric Amodio 4 years ago
parent
commit
61e616ce6e
9 changed files with 239 additions and 10 deletions
  1. +1
    -1
      src/webviews/apps/scss/popup.scss
  2. +9
    -0
      src/webviews/apps/settings/partials/blame.html
  3. +14
    -0
      src/webviews/apps/settings/partials/current-line.html
  4. +9
    -0
      src/webviews/apps/settings/partials/status-bar.html
  5. +34
    -1
      src/webviews/apps/settings/settings.html
  6. +69
    -4
      src/webviews/apps/shared/appWithConfigBase.ts
  7. +9
    -3
      src/webviews/apps/shared/dom.ts
  8. +21
    -0
      src/webviews/protocol.ts
  9. +73
    -1
      src/webviews/webviewBase.ts

+ 1
- 1
src/webviews/apps/scss/popup.scss View File

@ -3,7 +3,7 @@
cursor: default;
padding: 1em;
position: absolute;
top: 46px;
top: 72px;
width: 80vw;
min-width: 373px;
max-width: 472px;

+ 9
- 0
src/webviews/apps/settings/partials/blame.html View File

@ -58,6 +58,7 @@
type="text"
placeholder="${message|50?} ${agoOrDate|14-}"
data-setting
data-setting-preview
data-default-value="${message|50?} ${agoOrDate|14-}"
data-popup-trigger
/>
@ -66,6 +67,14 @@
</label>
</div>
<div id="blame.format.popup" class="popup hidden"></div>
<span class="setting__hint"
>Example:
<span
data-setting-preview="blame.format.format"
data-setting-preview-type="commit"
data-setting-preview-default="${message|50?} ${agoOrDate|14-}"
></span>
</span>
</div>
<div class="setting">

+ 14
- 0
src/webviews/apps/settings/partials/current-line.html View File

@ -66,6 +66,7 @@
type="text"
placeholder="${author, }${agoOrDate}${' via 'pullRequest}${ • message|50?}"
data-setting
data-setting-preview
data-default-value="${author, }${agoOrDate}${' via 'pullRequest}${ • message|50?}"
data-popup-trigger
disabled
@ -75,6 +76,14 @@
</label>
</div>
<div id="currentLine.format.popup" class="popup hidden"></div>
<span class="setting__hint"
>Example:
<span
data-setting-preview="currentLine.format"
data-setting-preview-type="commit"
data-setting-preview-default="${author, }${agoOrDate}${' via 'pullRequest}${ • message|50?}"
></span>
</span>
</div>
<div class="setting" data-enablement="currentLine.enabled">
@ -106,6 +115,11 @@
/>
<img
class="image__preview--overlay hidden"
src="#{root}/images/settings/current-line-blame-on+pr.png"
data-visibility="currentLine.enabled &amp; currentLine.pullRequests.enabled"
/>
<img
class="image__preview--overlay hidden"
src="#{root}/images/settings/current-line-blame-on-scrollable.png"
data-visibility="currentLine.enabled &amp; currentLine.scrollable"
/>

+ 9
- 0
src/webviews/apps/settings/partials/status-bar.html View File

@ -48,6 +48,7 @@
type="text"
placeholder="${author}, ${agoOrDate}${' via 'pullRequest}"
data-setting
data-setting-preview
data-default-value="${author}, ${agoOrDate}${' via 'pullRequest}"
data-popup-trigger
disabled
@ -57,6 +58,14 @@
</label>
</div>
<div id="statusBar.format.popup" class="popup hidden"></div>
<span class="setting__hint"
>Example:
<span
data-setting-preview="statusBar.format"
data-setting-preview-type="commit"
data-setting-preview-default="${author}, ${agoOrDate}${' via 'pullRequest}"
></span>
</span>
</div>
<div class="setting" data-enablement="statusBar.enabled">

+ 34
- 1
src/webviews/apps/settings/settings.html View File

@ -10,7 +10,7 @@
<table class="token-popup__table">
<tbody>
<tr>
<td>Commit Id</td>
<td>Commit SHA</td>
<td><span class="token" data-token="id">id</span></td>
</tr>
<tr>
@ -18,6 +18,10 @@
<td><span class="token" data-token="author">author</span></td>
</tr>
<tr>
<td>Commit Author (except you)</td>
<td><span class="token" data-token="authorNotYou">authorNotYou</span></td>
</tr>
<tr>
<td>Commit Author E-mail</td>
<td><span class="token" data-token="email">email</span></td>
</tr>
@ -51,6 +55,15 @@
<td><span class="token" data-token="agoOrDate">agoOrDate</span></td>
</tr>
<tr>
<td>
Commit or Authored Date (Short)<br /><i
>Short relative or absolute based on date setting<br />Committed vs Authored based on
setting</i
>
</td>
<td><span class="token" data-token="agoOrDateShort">agoOrDateShort</span></td>
</tr>
<tr>
<td>Authored Date<br /><i>Relative date</i></td>
<td><span class="token" data-token="authorAgo">authorAgo</span></td>
</tr>
@ -63,6 +76,10 @@
<td><span class="token" data-token="authorAgoOrDate">authorAgoOrDate</span></td>
</tr>
<tr>
<td>Authored Date (Short)<br /><i>Short relative or absolute date based on date setting</i></td>
<td><span class="token" data-token="authorAgoOrDateShort">authorAgoOrDateShort</span></td>
</tr>
<tr>
<td>Commit Date<br /><i>Relative date</i></td>
<td><span class="token" data-token="committerAgo">committerAgo</span></td>
</tr>
@ -75,6 +92,22 @@
<td><span class="token" data-token="committerAgoOrDate">committerAgoOrDate</span></td>
</tr>
<tr>
<td>Commit Date (Short)<br /><i>Short relative or absolute date based on date setting</i></td>
<td><span class="token" data-token="committerAgoOrDateShort">committerAgoOrDateShort</span></td>
</tr>
<tr>
<td>Pull Request<br /><i>Pull request (if any) that introduced the commit</i></td>
<td><span class="token" data-token="pullRequest">pullRequest</span></td>
</tr>
<tr>
<td>
Pull Request State<br /><i
>State (open, merged, closed) of the pull request (if any) that introduced the commit</i
>
</td>
<td><span class="token" data-token="pullRequestState">pullRequestState</span></td>
</tr>
<tr>
<td>Branch & Tag Tips<br /><i>Indicates if the commit is a tip of any branches or tags</i></td>
<td><span class="token" data-token="tips">tips</span></td>
</tr>

+ 69
- 4
src/webviews/apps/shared/appWithConfigBase.ts View File

@ -3,8 +3,10 @@
import {
AppStateWithConfig,
DidChangeConfigurationNotificationType,
DidPreviewConfigurationNotificationType,
IpcMessage,
onIpcNotification,
PreviewConfigurationCommandType,
UpdateConfigurationCommandType,
} from '../../protocol';
import { App } from './appBase';
@ -13,6 +15,17 @@ import { getDateFormatter } from '../shared/date';
const dateFormatter = getDateFormatter(new Date('Wed Jul 25 2018 19:18:00 GMT-0400'));
let ipcSequence = 0;
function nextIpcId() {
if (ipcSequence === Number.MAX_SAFE_INTEGER) {
ipcSequence = 1;
} else {
ipcSequence++;
}
return `${ipcSequence}`;
}
export abstract class AppWithConfig<TState extends AppStateWithConfig> extends App<TState> {
private _changes = Object.create(null) as Record<string, any>;
private _updating: boolean = false;
@ -213,8 +226,6 @@ export abstract class AppWithConfig extends A
}
protected onPopupMouseDown(element: HTMLElement, e: MouseEvent) {
// e.stopPropagation();
// e.stopImmediatePropagation();
e.preventDefault();
const el = e.target as HTMLElement;
@ -234,7 +245,25 @@ export abstract class AppWithConfig extends A
const input = setting.querySelector<HTMLInputElement>('input[type=text], input:not([type])');
if (input == null) return;
input.value += `\${${element.dataset.token}}`;
const token = `\${${element.dataset.token}}`;
let selectionStart = input.selectionStart;
if (selectionStart != null) {
input.value = `${input.value.substring(0, selectionStart)}${token}${input.value.substr(
input.selectionEnd ?? selectionStart,
)}`;
selectionStart += token.length;
} else {
selectionStart = input.value.length;
}
input.focus();
input.setSelectionRange(selectionStart, selectionStart);
if (selectionStart === input.value.length) {
input.scrollLeft = input.scrollWidth;
}
setTimeout(() => input.focus(), 250);
e.stopPropagation();
e.stopImmediatePropagation();
@ -363,7 +392,7 @@ export abstract class AppWithConfig extends A
private updatePreview(el: HTMLSpanElement, value?: string) {
switch (el.dataset.settingPreviewType) {
case 'date':
case 'date': {
if (value === undefined) {
value = this.getSettingValue<string>(el.dataset.settingPreview!);
}
@ -374,7 +403,43 @@ export abstract class AppWithConfig extends A
el.innerText = value == null ? '' : dateFormatter.format(value);
break;
}
case 'commit': {
if (value === undefined) {
value = this.getSettingValue<string>(el.dataset.settingPreview!);
}
if (value == null || value.length === 0) {
value = el.dataset.settingPreviewDefault;
}
if (value == null) {
el.innerText = '';
return;
}
const id = nextIpcId();
const disposable = DOM.on(window, 'message', (e: MessageEvent) => {
const msg = e.data as IpcMessage;
if (msg.method === DidPreviewConfigurationNotificationType.method && msg.params.id === id) {
disposable.dispose();
onIpcNotification(DidPreviewConfigurationNotificationType, msg, params => {
el.innerText = params.preview ?? '';
});
}
});
this.sendCommand(PreviewConfigurationCommandType, {
key: el.dataset.settingPreview!,
type: 'commit',
id: id,
format: value,
});
break;
}
default:
break;
}

+ 9
- 3
src/webviews/apps/shared/dom.ts View File

@ -19,10 +19,16 @@ export namespace DOM {
listener: (this: T, ev: DocumentEventMap[K]) => any,
options?: boolean | AddEventListenerOptions,
): Disposable;
export function on<K extends keyof DocumentEventMap, T extends Element>(
selectorOrElement: string | Document | Element,
export function on<K extends keyof WindowEventMap, T extends Element>(
el: Window,
name: K,
listener: (this: T, ev: DocumentEventMap[K]) => any,
listener: (this: T, ev: WindowEventMap[K]) => any,
options?: boolean | AddEventListenerOptions,
): Disposable;
export function on<K extends keyof (DocumentEventMap | WindowEventMap), T extends Element>(
selectorOrElement: string | Window | Document | Element,
name: K,
listener: (this: T, ev: (DocumentEventMap | WindowEventMap)[K]) => any,
options?: boolean | AddEventListenerOptions,
el?: Element,
): Disposable {

+ 21
- 0
src/webviews/protocol.ts View File

@ -56,6 +56,27 @@ export const UpdateConfigurationCommandType = new IpcCommandType
'configuration/update',
);
export interface CommitPreviewConfigurationCommandParams {
key: string;
id: string;
type: 'commit';
format: string;
}
type PreviewConfigurationCommandParams = CommitPreviewConfigurationCommandParams;
export const PreviewConfigurationCommandType = new IpcCommandType<PreviewConfigurationCommandParams>(
'configuration/preview',
);
export interface DidPreviewConfigurationNotificationParams {
id: string;
preview: string;
}
export const DidPreviewConfigurationNotificationType = new IpcNotificationType<
DidPreviewConfigurationNotificationParams
>('configuration/didPreview');
export interface SettingsDidRequestJumpToNotificationParams {
anchor: string;
}

+ 73
- 1
src/webviews/webviewBase.ts View File

@ -13,18 +13,21 @@ import {
window,
workspace,
} from 'vscode';
import { Commands } from '../commands';
import { configuration } from '../configuration';
import { Container } from '../container';
import { CommitFormatter, GitBlameCommit, PullRequest, PullRequestState } from '../git/git';
import { Logger } from '../logger';
import {
DidChangeConfigurationNotificationType,
DidPreviewConfigurationNotificationType,
IpcMessage,
IpcNotificationParamsOf,
IpcNotificationType,
onIpcCommand,
PreviewConfigurationCommandType,
UpdateConfigurationCommandType,
} from './protocol';
import { Commands } from '../commands';
let ipcSequence = 0;
function nextIpcId() {
@ -131,6 +134,75 @@ export abstract class WebviewBase implements Disposable {
});
break;
case PreviewConfigurationCommandType.method:
onIpcCommand(PreviewConfigurationCommandType, e, async params => {
switch (params.type) {
case 'commit': {
const commit = new GitBlameCommit(
'~/code/eamodio/vscode-gitlens-demo',
'fe26af408293cba5b4bfd77306e1ac9ff7ccaef8',
'You',
'eamodio@gmail.com',
new Date('2016-11-12T20:41:00.000Z'),
new Date('2020-11-01T06:57:21.000Z'),
'Supercharged',
'code.ts',
undefined,
'3ac1d3f51d7cf5f438cc69f25f6740536ad80fef',
'code.ts',
[],
);
let includePullRequest = false;
switch (params.key) {
case configuration.name('currentLine', 'format'):
includePullRequest = Container.config.currentLine.pullRequests.enabled;
break;
case configuration.name('statusBar', 'format'):
includePullRequest = Container.config.statusBar.pullRequests.enabled;
break;
}
let pr: PullRequest | undefined;
if (includePullRequest) {
pr = new PullRequest(
'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/eamodio/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: Container.config.defaultDateFormat,
pullRequestOrRemote: pr,
messageTruncateAtNewLine: true,
});
} catch {
preview = 'Invalid format';
}
await this.notify(DidPreviewConfigurationNotificationType, {
id: params.id,
preview: preview,
});
}
}
});
break;
default:
break;
}

Loading…
Cancel
Save