add mentions

This commit is contained in:
2025-12-02 06:13:50 +03:00
parent 414298b4b4
commit 1d5d5a8c64
28 changed files with 366 additions and 64 deletions

View File

@@ -6,6 +6,16 @@ from pygments.lexers import get_lexer_by_name
from pygments.util import ClassNotFound as PygmentsClassNotFound
import re
class BabycodeParseResult:
def __init__(self, result, mentions=[]):
self.result = result
self.mentions = mentions
def __str__(self):
return self.result
BABYCODE_VERSION = 5
NAMED_COLORS = [
@@ -78,6 +88,9 @@ def tag_list(children):
return " ".join([f"<li>{x}</li>" for x in list_body.split("\1") if x])
def tag_color(children, attr, surrounding):
if not attr:
return f"[color]{children}[/color]"
hex_re = r"^#?([0-9a-f]{6}|[0-9a-f]{3})$"
potential_color = attr.lower().strip()
@@ -206,6 +219,24 @@ def is_inline(e):
return e['type'] != 'rule'
def make_mention(e, mentions):
from ..models import Users
from flask import url_for
target_user = Users.find({'username': e['name'].lower()})
if not target_user:
return f"@{e['name']}"
mention_data = {
'mention_text': f"@{e['name']}",
'mentioned_user_id': int(target_user.id),
"start": e['start'],
"end": e['end'],
}
if mention_data not in mentions:
mentions.append(mention_data)
return f"<a class='mention{' display' if target_user.has_display_name() else ''}' href='{url_for('users.page', username=target_user.username)}' title='@{target_user.username}' data-init='highlightMentions' data-username='{target_user.username}'>{'@' if not target_user.has_display_name() else ''}{target_user.get_readable_name()}</a>"
def should_collapse(text, surrounding):
if not isinstance(text, str):
return False
@@ -218,15 +249,19 @@ def should_collapse(text, surrounding):
return False
def babycode_to_html(s, banned_tags=None):
allowed_tags = list(TAGS.keys())
def sanitize(s):
return escape(s.strip().replace('\r\n', '\n').replace('\r', '\n'))
def babycode_to_html(s, banned_tags={}):
allowed_tags = set(TAGS.keys())
if banned_tags is not None:
for tag in banned_tags:
allowed_tags.remove(tag)
subj = escape(s.strip().replace('\r\n', '\n').replace('\r', '\n'))
allowed_tags.discard(tag)
subj = sanitize(s)
parser = Parser(subj)
parser.valid_bbcode_tags = allowed_tags
parser.bbcode_tags_only_text_children = TEXT_ONLY
parser.mentions_allowed = '@mention' not in banned_tags
parser.valid_emotes = EMOJI.keys()
uncollapsed = parser.parse()
@@ -241,6 +276,7 @@ def babycode_to_html(s, banned_tags=None):
elements.append(e)
out = ""
mentions = []
def fold(element, nobr, surrounding):
if isinstance(element, str):
if nobr:
@@ -266,6 +302,8 @@ def babycode_to_html(s, banned_tags=None):
return EMOJI[element['name']]
case "rule":
return "<hr>"
case "mention":
return make_mention(element, mentions)
for i in range(len(elements)):
e = elements[i]
@@ -274,4 +312,4 @@ def babycode_to_html(s, banned_tags=None):
elements[i + 1] if i+1 < len(elements) else None
)
out = out + fold(e, False, surrounding)
return out
return BabycodeParseResult(out, mentions)

View File

@@ -6,12 +6,14 @@ PAT_EMOTE = r"[^\s:]"
PAT_BBCODE_TAG = r"\w"
PAT_BBCODE_ATTR = r"[^\]]"
PAT_LINK = r"https?:\/\/[\w\-_.?:\/=&~@#%]+[\w\-\/]"
PAT_MENTION = r'[a-zA-Z0-9_-]'
class Parser:
def __init__(self, src_str):
self.valid_bbcode_tags = []
self.valid_bbcode_tags = {}
self.valid_emotes = []
self.bbcode_tags_only_text_children = [],
self.bbcode_tags_only_text_children = []
self.mentions_allowed = True
self.source = src_str
self.position = 0
self.position_stack = []
@@ -206,6 +208,25 @@ class Parser:
"url": word
}
def parse_mention(self):
if not self.mentions_allowed:
return None
self.save_position()
if not self.check_char('@'):
self.restore_position()
return None
mention = self.match_pattern(PAT_MENTION)
self.forget_position()
return {
"type": "mention",
"name": mention,
"start": self.position - len(mention) - 1,
"end": self.position,
}
def parse_element(self, siblings):
if self.is_end_of_source():
@@ -214,7 +235,8 @@ class Parser:
element = self.parse_emote() \
or self.parse_bbcode() \
or self.parse_rule() \
or self.parse_link()
or self.parse_link() \
or self.parse_mention()
if element is None:
if len(siblings) > 0: