Skip to content

Commit 110a402

Browse files
Copilotalexr00
andcommitted
Add emoji support to label rendering in markdown and webviews
Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com>
1 parent f90e303 commit 110a402

File tree

6 files changed

+51
-4
lines changed

6 files changed

+51
-4
lines changed

src/github/issueOverview.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as vscode from 'vscode';
88
import { CloseResult } from '../../common/views';
99
import { openPullRequestOnGitHub } from '../commands';
1010
import { COPILOT_ACCOUNTS, IComment } from '../common/comment';
11+
import { emojify, ensureEmojis } from '../common/emoji';
1112
import Logger from '../common/logger';
1213
import { PR_SETTINGS_NAMESPACE, WEBVIEW_REFRESH_INTERVAL } from '../common/settingKeys';
1314
import { ITelemetry } from '../common/telemetry';
@@ -42,6 +43,7 @@ export class IssueOverviewPanel<TItem extends IssueModel = IssueModel> extends W
4243
issue: IssueModel,
4344
toTheSide: Boolean = false,
4445
) {
46+
await ensureEmojis(folderRepositoryManager.context);
4547
const activeColumn = toTheSide
4648
? vscode.ViewColumn.Beside
4749
: vscode.window.activeTextEditor
@@ -194,6 +196,11 @@ export class IssueOverviewPanel<TItem extends IssueModel = IssueModel> extends W
194196
protected getInitializeContext(currentUser: IAccount, issue: IssueModel, timelineEvents: TimelineEvent[], repositoryAccess: RepoAccessAndMergeMethods, viewerCanEdit: boolean, assignableUsers: IAccount[]): Issue {
195197
const hasWritePermission = repositoryAccess!.hasWritePermission;
196198
const canEdit = hasWritePermission || viewerCanEdit;
199+
const labels = issue.item.labels.map(label => ({
200+
...label,
201+
name: emojify(label.name)
202+
}));
203+
197204
const context: Issue = {
198205
owner: issue.remote.owner,
199206
repo: issue.remote.repositoryName,
@@ -204,7 +211,7 @@ export class IssueOverviewPanel<TItem extends IssueModel = IssueModel> extends W
204211
createdAt: issue.createdAt,
205212
body: issue.body,
206213
bodyHTML: issue.bodyHTML,
207-
labels: issue.item.labels,
214+
labels: labels,
208215
author: issue.author,
209216
state: issue.state,
210217
events: timelineEvents,

src/github/markdownUtils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import * as marked from 'marked';
77
import 'url-search-params-polyfill';
88
import * as vscode from 'vscode';
9+
import { ensureEmojis } from '../common/emoji';
910
import Logger from '../common/logger';
1011
import { CODE_PERMALINK, findCodeLinkLocally } from '../issues/issueLinkLookup';
1112
import { PullRequestDefaults } from './folderRepositoryManager';
@@ -188,6 +189,7 @@ export async function issueMarkdown(
188189
markdown.appendMarkdown(body + ' \n');
189190

190191
if (issue.item.labels.length > 0) {
192+
await ensureEmojis(context);
191193
markdown.appendMarkdown('&nbsp; \n');
192194
issue.item.labels.forEach(label => {
193195
markdown.appendMarkdown(

src/github/utils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { GitApiImpl } from '../api/api1';
1212
import { AuthProvider, GitHubServerType } from '../common/authentication';
1313
import { COPILOT_ACCOUNTS, IComment, IReviewThread, SubjectType } from '../common/comment';
1414
import { DiffHunk, parseDiffHunk } from '../common/diffHunk';
15+
import { emojify } from '../common/emoji';
1516
import { GitHubRef } from '../common/githubRef';
1617
import Logger from '../common/logger';
1718
import { Remote } from '../common/remote';
@@ -1746,7 +1747,8 @@ export function vscodeDevPrLink(pullRequest: IssueModel) {
17461747
export function makeLabel(label: ILabel): string {
17471748
const isDarkTheme = vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.Dark;
17481749
const labelColor = gitHubLabelColor(label.color, isDarkTheme, true);
1749-
return `<span style="color:${labelColor.textColor};background-color:${labelColor.backgroundColor};border-radius:10px;">&nbsp;&nbsp;${label.name.trim()}&nbsp;&nbsp;</span>`;
1750+
const labelName = emojify(label.name.trim());
1751+
return `<span style="color:${labelColor.textColor};background-color:${labelColor.backgroundColor};border-radius:10px;">&nbsp;&nbsp;${labelName}&nbsp;&nbsp;</span>`;
17501752
}
17511753

17521754

src/lm/tools/displayIssuesTool.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
'use strict';
66

77
import * as vscode from 'vscode';
8+
import { ensureEmojis } from '../../common/emoji';
89
import Logger from '../../common/logger';
910
import { reviewerLabel } from '../../github/interface';
1011
import { makeLabel } from '../../github/utils';
@@ -29,7 +30,7 @@ Here are the possible columns:
2930
export class DisplayIssuesTool extends ToolBase<DisplayIssuesParameters> {
3031
public static readonly toolId = 'github-pull-request_renderIssues';
3132
private static ID = 'DisplayIssuesTool';
32-
constructor(chatParticipantState: ChatParticipantState) {
33+
constructor(private readonly context: vscode.ExtensionContext, chatParticipantState: ChatParticipantState) {
3334
super(chatParticipantState);
3435
}
3536

@@ -144,6 +145,7 @@ export class DisplayIssuesTool extends ToolBase<DisplayIssuesParameters> {
144145
}
145146

146147
async invoke(options: vscode.LanguageModelToolInvocationOptions<DisplayIssuesParameters>, token: vscode.CancellationToken): Promise<vscode.LanguageModelToolResult | undefined> {
148+
await ensureEmojis(this.context);
147149
const issueItemsInfo: vscode.LanguageModelTextPart | undefined = this.chatParticipantState.firstUserMessage;
148150
const issueItems: IssueSearchResultItem[] | undefined = options.input.arrayOfIssues;
149151
if (!issueItems || issueItems.length === 0) {

src/lm/tools/tools.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,5 @@ function registerCopilotAgentTools(context: vscode.ExtensionContext, copilotRemo
5050
function registerSearchTools(context: vscode.ExtensionContext, credentialStore: CredentialStore, repositoriesManager: RepositoriesManager, chatParticipantState: ChatParticipantState) {
5151
context.subscriptions.push(vscode.lm.registerTool(ConvertToSearchSyntaxTool.toolId, new ConvertToSearchSyntaxTool(credentialStore, repositoriesManager, chatParticipantState)));
5252
context.subscriptions.push(vscode.lm.registerTool(SearchTool.toolId, new SearchTool(credentialStore, repositoriesManager, chatParticipantState)));
53-
context.subscriptions.push(vscode.lm.registerTool(DisplayIssuesTool.toolId, new DisplayIssuesTool(chatParticipantState)));
53+
context.subscriptions.push(vscode.lm.registerTool(DisplayIssuesTool.toolId, new DisplayIssuesTool(context, chatParticipantState)));
5454
}

src/test/github/emoji.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { default as assert } from 'assert';
7+
import { emojify } from '../../common/emoji';
8+
import { makeLabel } from '../../github/utils';
9+
10+
describe('emoji rendering in labels', function () {
11+
it('should return original text when emoji map is not loaded', function () {
12+
const input = 'papercut :drop_of_blood:';
13+
const result = emojify(input);
14+
// Since emoji map isn't loaded, it should return the original text
15+
assert.strictEqual(result, input);
16+
});
17+
18+
it('should process label names through emojify', function () {
19+
const label = { name: 'papercut :drop_of_blood:', color: 'red' };
20+
const result = makeLabel(label);
21+
// The label name should go through emojify (even if it returns the original)
22+
assert.ok(result.includes('papercut :drop_of_blood:'));
23+
assert.ok(result.includes('color:'));
24+
assert.ok(result.includes('background-color:'));
25+
});
26+
27+
it('should handle labels without emoji codes', function () {
28+
const label = { name: 'bug', color: 'red' };
29+
const result = makeLabel(label);
30+
assert.ok(result.includes('bug'));
31+
assert.ok(result.includes('color:'));
32+
assert.ok(result.includes('background-color:'));
33+
});
34+
});

0 commit comments

Comments
 (0)