Skip to content

Commit 91c7eaf

Browse files
authored
add audio cues for reviewing a diff editor (microsoft#166413)
1 parent 5588a85 commit 91c7eaf

25 files changed

+70
-31
lines changed

src/vs/editor/browser/widget/diffEditorWidget.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,11 @@ function createDecoration(startLineNumber: number, startColumn: number, endLineN
18781878
};
18791879
}
18801880

1881+
const enum DiffEditorLineClasses {
1882+
Insert = 'line-insert',
1883+
Delete = 'line-delete'
1884+
}
1885+
18811886
const DECORATIONS = {
18821887

18831888
arrowRevertChange: ModelDecorationOptions.register({
@@ -1907,27 +1912,27 @@ const DECORATIONS = {
19071912

19081913
lineInsert: ModelDecorationOptions.register({
19091914
description: 'diff-editor-line-insert',
1910-
className: 'line-insert',
1915+
className: DiffEditorLineClasses.Insert,
19111916
marginClassName: 'gutter-insert',
19121917
isWholeLine: true
19131918
}),
19141919
lineInsertWithSign: ModelDecorationOptions.register({
19151920
description: 'diff-editor-line-insert-with-sign',
1916-
className: 'line-insert',
1921+
className: DiffEditorLineClasses.Insert,
19171922
linesDecorationsClassName: 'insert-sign ' + ThemeIcon.asClassName(diffInsertIcon),
19181923
marginClassName: 'gutter-insert',
19191924
isWholeLine: true
19201925
}),
19211926

19221927
lineDelete: ModelDecorationOptions.register({
19231928
description: 'diff-editor-line-delete',
1924-
className: 'line-delete',
1929+
className: DiffEditorLineClasses.Delete,
19251930
marginClassName: 'gutter-delete',
19261931
isWholeLine: true
19271932
}),
19281933
lineDeleteWithSign: ModelDecorationOptions.register({
19291934
description: 'diff-editor-line-delete-with-sign',
1930-
className: 'line-delete',
1935+
className: DiffEditorLineClasses.Delete,
19311936
linesDecorationsClassName: 'delete-sign ' + ThemeIcon.asClassName(diffRemoveIcon),
19321937
marginClassName: 'gutter-delete',
19331938
isWholeLine: true

src/vs/editor/browser/widget/diffReview.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
3333
import { ILanguageIdCodec } from 'vs/editor/common/languages';
3434
import { ILanguageService } from 'vs/editor/common/languages/language';
3535
import { ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer';
36+
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
3637

3738
const DIFF_LINES_PADDING = 3;
3839

@@ -66,6 +67,11 @@ class DiffEntry {
6667
}
6768
}
6869

70+
const enum DiffEditorLineClasses {
71+
Insert = 'line-insert',
72+
Delete = 'line-delete'
73+
}
74+
6975
class Diff {
7076
readonly entries: DiffEntry[];
7177

@@ -95,7 +101,8 @@ export class DiffReview extends Disposable {
95101

96102
constructor(
97103
diffEditor: DiffEditorWidget,
98-
@ILanguageService private readonly _languageService: ILanguageService
104+
@ILanguageService private readonly _languageService: ILanguageService,
105+
@IAudioCueService private readonly _audioCueService: IAudioCueService
99106
) {
100107
super();
101108
this._diffEditor = diffEditor;
@@ -149,7 +156,7 @@ export class DiffReview extends Disposable {
149156
|| e.equals(KeyMod.Alt | KeyCode.DownArrow)
150157
) {
151158
e.preventDefault();
152-
this._goToRow(this._getNextRow());
159+
this._goToRow(this._getNextRow(), 'next');
153160
}
154161

155162
if (
@@ -158,7 +165,7 @@ export class DiffReview extends Disposable {
158165
|| e.equals(KeyMod.Alt | KeyCode.UpArrow)
159166
) {
160167
e.preventDefault();
161-
this._goToRow(this._getPrevRow());
168+
this._goToRow(this._getPrevRow(), 'previous');
162169
}
163170

164171
if (
@@ -215,7 +222,7 @@ export class DiffReview extends Disposable {
215222
this._isVisible = true;
216223
this._diffEditor.doLayout();
217224
this._render();
218-
this._goToRow(this._getNextRow());
225+
this._goToRow(this._getPrevRow(), 'previous');
219226
}
220227

221228
public next(): void {
@@ -250,7 +257,7 @@ export class DiffReview extends Disposable {
250257
this._isVisible = true;
251258
this._diffEditor.doLayout();
252259
this._render();
253-
this._goToRow(this._getNextRow());
260+
this._goToRow(this._getNextRow(), 'next');
254261
}
255262

256263
private accept(): void {
@@ -312,12 +319,18 @@ export class DiffReview extends Disposable {
312319
return null;
313320
}
314321

315-
private _goToRow(row: HTMLElement): void {
316-
const prev = this._getCurrentFocusedRow();
322+
private _goToRow(row: HTMLElement, type?: 'next' | 'previous'): void {
323+
const current = this._getCurrentFocusedRow();
317324
row.tabIndex = 0;
318325
row.focus();
319-
if (prev && prev !== row) {
320-
prev.tabIndex = -1;
326+
if (current && current !== row) {
327+
current.tabIndex = -1;
328+
}
329+
const element = !type ? current : type === 'next' ? current?.nextElementSibling : current?.previousElementSibling;
330+
if (element?.classList.contains(DiffEditorLineClasses.Insert)) {
331+
this._audioCueService.playAudioCue(AudioCue.diffLineInserted, true);
332+
} else if (element?.classList.contains(DiffEditorLineClasses.Delete)) {
333+
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, true);
321334
}
322335
this.scrollbar.scanDomNode();
323336
}

src/vs/editor/standalone/browser/standaloneCodeEditor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon
495495
@IConfigurationService configurationService: IConfigurationService,
496496
@IContextMenuService contextMenuService: IContextMenuService,
497497
@IEditorProgressService editorProgressService: IEditorProgressService,
498-
@IClipboardService clipboardService: IClipboardService,
498+
@IClipboardService clipboardService: IClipboardService
499499
) {
500500
const options = { ..._options };
501501
updateConfigurationService(configurationService, options, true);

src/vs/workbench/contrib/audioCues/browser/audioCueService.ts renamed to src/vs/platform/audioCues/browser/audioCueService.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const IAudioCueService = createDecorator<IAudioCueService>('audioCue');
1717

1818
export interface IAudioCueService {
1919
readonly _serviceBrand: undefined;
20-
playAudioCue(cue: AudioCue): Promise<void>;
20+
playAudioCue(cue: AudioCue, allowManyInParallel?: boolean): Promise<void>;
2121
playAudioCues(cues: AudioCue[]): Promise<void>;
2222
isEnabled(cue: AudioCue): IObservable<boolean>;
2323

@@ -39,9 +39,9 @@ export class AudioCueService extends Disposable implements IAudioCueService {
3939
super();
4040
}
4141

42-
public async playAudioCue(cue: AudioCue): Promise<void> {
42+
public async playAudioCue(cue: AudioCue, allowManyInParallel = false): Promise<void> {
4343
if (this.isEnabled(cue).get()) {
44-
await this.playSound(cue.sound);
44+
await this.playSound(cue.sound, allowManyInParallel);
4545
}
4646
}
4747

@@ -70,7 +70,7 @@ export class AudioCueService extends Disposable implements IAudioCueService {
7070
this.playingSounds.add(sound);
7171

7272
const url = FileAccess.asBrowserUri(
73-
`vs/workbench/contrib/audioCues/browser/media/${sound.fileName}`
73+
`vs/platform/audioCues/common/media/${sound.fileName}`
7474
).toString();
7575
const audio = new Audio(url);
7676
audio.volume = this.getVolumeInPercent() / 100;
@@ -164,6 +164,8 @@ export class Sound {
164164
public static readonly taskCompleted = Sound.register({ fileName: 'taskCompleted.mp3' });
165165
public static readonly taskFailed = Sound.register({ fileName: 'taskFailed.mp3' });
166166
public static readonly terminalBell = Sound.register({ fileName: 'terminalBell.mp3' });
167+
public static readonly diffLineInserted = Sound.register({ fileName: 'diffLineInserted.mp3' });
168+
public static readonly diffLineDeleted = Sound.register({ fileName: 'diffLineDeleted.mp3' });
167169

168170
private constructor(public readonly fileName: string) { }
169171
}
@@ -247,6 +249,18 @@ export class AudioCue {
247249
settingsKey: 'audioCues.terminalBell'
248250
});
249251

252+
public static readonly diffLineInserted = AudioCue.register({
253+
name: localize('audioCues.diffLineInserted', 'Diff Line Inserted'),
254+
sound: Sound.diffLineInserted,
255+
settingsKey: 'audioCues.diffLineInserted'
256+
});
257+
258+
public static readonly diffLineDeleted = AudioCue.register({
259+
name: localize('audioCues.diffLineDeleted', 'Diff Line Deleted'),
260+
sound: Sound.diffLineDeleted,
261+
settingsKey: 'audioCues.diffLineDeleted'
262+
});
263+
250264
private constructor(
251265
public readonly sound: Sound,
252266
public readonly name: string,
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)