Skip to content

Commit ae2a69d

Browse files
committed
Add chat command for user mention
1 parent 98ff95d commit ae2a69d

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) Jupyter Development Team.
3+
* Distributed under the terms of the Modified BSD License.
4+
*/
5+
6+
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
7+
import {
8+
IChatCommandProvider,
9+
IChatCommandRegistry,
10+
ChatCommand,
11+
IInputModel
12+
} from '@jupyter/chat';
13+
import { LabChatModel } from 'jupyterlab-chat';
14+
import { JSONObject } from '@lumino/coreutils';
15+
16+
export class MentionCommandProvider implements IChatCommandProvider {
17+
public id: string = 'jupyter-chat:mention-commands';
18+
19+
// regex used to test the current word
20+
private _regex: RegExp = /^@[\w-]*:?/;
21+
22+
async getChatCommands(inputModel: IInputModel, chatModel: LabChatModel) {
23+
const match = inputModel.currentWord?.match(this._regex)?.[0];
24+
if (!match) {
25+
return [];
26+
}
27+
28+
// Get the user list from the chat file.
29+
const users = Object.values(chatModel.sharedModel.users).map(user => {
30+
user = user as JSONObject;
31+
return (user.display_name ?? user.name ?? user.username) as string;
32+
});
33+
34+
// Add the users connected to the chat (even if they never sent a message).
35+
chatModel.sharedModel.awareness.getStates().forEach(value => {
36+
const user = value.user;
37+
if (!user) {
38+
return;
39+
}
40+
const username = (user.display_name ??
41+
user.name ??
42+
user.username) as string;
43+
if (username && !users.includes(username)) {
44+
users.push(username);
45+
}
46+
});
47+
48+
// Build the commands for each user.
49+
const commands = users
50+
.sort()
51+
.filter(user => `@${user.replace(/ /g, '-')}`.startsWith(match))
52+
.map(user => {
53+
return {
54+
name: `@${user.replace(/ /g, '-')}`,
55+
replaceWith: `@${user}`,
56+
providerId: this.id
57+
};
58+
});
59+
return commands;
60+
}
61+
62+
async handleChatCommand(
63+
command: ChatCommand,
64+
inputModel: IInputModel,
65+
chatModel: LabChatModel
66+
): Promise<void> {
67+
// no handling needed because `replaceWith` is set in each command.
68+
return;
69+
}
70+
}
71+
72+
export const mentionCommandsPlugin: JupyterFrontEndPlugin<void> = {
73+
id: 'jupyterlab-chat-extension:mentionCommandsPlugin',
74+
description: 'Plugin which adds user mention commands.',
75+
autoStart: true,
76+
requires: [IChatCommandRegistry],
77+
activate: (app, registry: IChatCommandRegistry) => {
78+
registry.addProvider(new MentionCommandProvider());
79+
}
80+
};

python/jupyterlab-chat/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {
6464
} from 'jupyterlab-chat';
6565
import { chatCommandRegistryPlugin } from './chat-commands/plugins';
6666
import { emojiCommandsPlugin } from './chat-commands/providers/emoji';
67+
import { mentionCommandsPlugin } from './chat-commands/providers/user-mention';
6768

6869
const FACTORY = 'Chat';
6970

@@ -799,5 +800,6 @@ export default [
799800
docFactories,
800801
selectionWatcher,
801802
chatCommandRegistryPlugin,
802-
emojiCommandsPlugin
803+
emojiCommandsPlugin,
804+
mentionCommandsPlugin
803805
];

0 commit comments

Comments
 (0)