50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
/**
|
|
* Shared mention trigger detection.
|
|
*
|
|
* Detects when the user has typed "@" followed by an optional query
|
|
* at the cursor position, and returns the match info for opening
|
|
* a mention panel.
|
|
*/
|
|
|
|
/** Characters that BLOCK @ trigger (only @ itself, to prevent @@). */
|
|
const BLOCKED_BEFORE_AT = /[@]/;
|
|
|
|
export interface MentionTriggerMatch {
|
|
/** Index of the @ character in the full text. */
|
|
atIndex: number;
|
|
/** The query text after @ (may be empty). */
|
|
query: string;
|
|
}
|
|
|
|
/**
|
|
* Check whether the text before the cursor contains an active @ mention trigger.
|
|
*
|
|
* Rules:
|
|
* - @ must be at position 0, or preceded by a boundary character
|
|
* (whitespace, Chinese/English punctuation, brackets).
|
|
* - The query (text after @ up to the cursor) must not contain
|
|
* any boundary character or space.
|
|
* - Returns null if no trigger is found.
|
|
*/
|
|
export function detectMentionTrigger(textBeforeCursor: string): MentionTriggerMatch | null {
|
|
const atIdx = textBeforeCursor.lastIndexOf("@");
|
|
if (atIdx < 0) return null;
|
|
|
|
// @ must be at start or not preceded by another @
|
|
if (atIdx > 0 && BLOCKED_BEFORE_AT.test(textBeforeCursor[atIdx - 1])) {
|
|
return null;
|
|
}
|
|
|
|
const query = textBeforeCursor.slice(atIdx + 1);
|
|
|
|
// Query must not contain spaces or punctuation that would break a mention token
|
|
if (/[\s,。、;:!??!.,;:(){}[\]<>""''《》【】@]/.test(query)) {
|
|
return null;
|
|
}
|
|
|
|
return { atIndex: atIdx, query };
|
|
}
|
|
|
|
/** Token pattern for @图片1, @视频1, @文本1, @音频1, @附件1, @素材1, etc. */
|
|
export const MENTION_TOKEN_RE = /@(?:图片|视频|文本|音频|附件|素材)\d+/g;
|