接下来还是 @stanley_1ab 开发的防止头像裂开的 patch。 如果你用的是 elpa 的话,执行下面这个 elisp,然后重启 emacs 就行了
(let ((telega-path (package-desc-dir (package-get-descriptor
'telega))))
(shell-command (concat "cd " telega-path " && " "curl
https://github.com/zevlg/telega.el/commit/e1c9de039c1cf20048fb22b740175917d17f9110.patch
| patch -p1"))
(byte-recompile-directory telega-path 0))
非 elpa 用户请自行前往代码中的 patch 连接 副作用是 @replies 里面的头像会裂开。
嫌麻烦的人也可以直接复制以下的同名函数进行覆盖就可以了
;; avatar
(defcustom telega-avatar-slice-2-raise 0.5
"Raise of the second slice of the avatar.
Setting this value to a higher number will avoid gaps between avatar,
but increase the distance between username and text body."
:package-version '(telega . "0.8.163")
:type '(choice 'center integer)
:type 'integer
:group 'telega)
(defun telega-ins--ascent-percent (string)
"Find the max of the fonts descent in STRING and convert it to ascent percent.
If STRING is empty or can't find the telega current buffer frame,
then return \\='center."
(if-let* ((buffer (or telega--current-buffer (current-buffer)))
(window (get-buffer-window buffer))
(frame (window-frame window))
(default-font (face-font 'default frame))
(img-xheight (aref (font-info default-font frame) 3))
(max-descent (aref (font-info default-font frame) 9)))
(progn
(dotimes (i (length string))
(when-let* ((font (font-at i window string))
(descent (aref (font-info font frame) 9))
(max? (> descent max-descent)))
(setq max-descent descent)))
(if (= max-descent -1)
'center
(round (* 100 (- 1 (/ (float max-descent) img-xheight))))))
'center))
(defun telega-ins--image (img &optional slice-num &rest props)
"Insert image IMG generated by telega.
Uses internal `:telega-text' to keep correct column.
If SLICE-NUM is specified, then insert single slice.
SLICE-NUM can be a list in form (SLICE-NUM SLICE-Y SLICE-H).
Special property `:no-display-if' is supported in PROPS to
ommit image display if value is for this property is non-nil.
Property `:image-ascent' is used to specify image ascent.
It is useful to adjust the position of the sliced avatar.
Property `:image-raise' is used to specify display raise.
It is useful to adjust the position of the sliced avatar."
;; NOTE: IMG might be nil if `telega-use-images' is nil
;; See https://github.com/zevlg/telega.el/issues/274
(if (not img)
(telega-ins "<IMAGE>")
;; NOTE: do not check SLICE-NUM
(let ((slice (cond ((numberp slice-num)
(list 0 (telega-chars-xheight slice-num)
1.0 (telega-chars-xheight 1)))
((listp slice-num)
(prog1
(list 0 (nth 1 slice-num)
1.0 (nth 2 slice-num))
(setq slice-num (nth 0 slice-num))))
(slice-num
(error "Invalid slice-num: %S" slice-num)))))
(telega-ins--with-props
(nconc (list 'rear-nonsticky '(display))
(unless (plist-get props :no-display-if)
(when-let ((ascent (plist-get props :image-ascent)))
(setf (image-property img :ascent) ascent))
(let ((display-specs (list img))
(image-raise (plist-get props :image-raise)))
(when slice
(push (cons 'slice slice) display-specs))
(when image-raise
(push `(raise ,image-raise) display-specs))
(list 'display display-specs)))
props)
(telega-ins
(or (plist-get props :telega-text)
(telega-image--telega-text img slice-num)
;; Otherwise use slow `image-size' to get correct
;; `:telega-text'
(make-string (telega-chars-in-width
(or (plist-get (cdr img) :width)
(progn
(telega-debug "WARN: `image-size' used for %S" img)
(cl-assert img)
(car (image-size img t (telega-x-frame))))))
?X)))))))
(defun telega-ins--user (user &optional member show-phone-p)
"Insert USER, aligning multiple lines at current column.
MEMBER specifies corresponding \"ChatMember\" object.
If SHOW-PHONE-P is non-nil, then show USER's phone number."
(let ((avatar (telega-msg-sender-avatar-image user))
(username (if (telega-user-p user)
(telega-user-title user 'full-name)
(cl-assert (telega-chat-p user))
(telega-chat-title user)))
(off-column (telega-current-column)))
(telega-ins--image avatar 0
:image-ascent (telega-ins--ascent-percent username)
:no-display-if (not telega-user-show-avatars))
(telega-ins--msg-sender user :with-username-p 'telega-username)
(telega-ins--with-face 'telega-shadow
(when (and member
(telega-ins-prefix " ("
(telega-ins--chat-member-status
(plist-get member :status))))
(telega-ins ")")))
(when show-phone-p
(when-let ((phone-number (telega-tl-str user :phone_number)))
(telega-ins--with-face 'telega-shadow
(telega-ins " • "))
(telega-ins "+" phone-number)))
;; Insert (him)in<-->out(me) relationship
(when (and telega-user-show-relationship
(not (telega-me-p user)))
(telega-ins " ")
(telega-ins--user-relationship user))
;; Block/scam mark, without requesting
(when (telega-user-match-p user 'is-blocked)
(telega-ins " " (telega-symbol 'blocked)))
(telega-ins "\n")
(telega-ins (make-string off-column ?\s))
(telega-ins--image avatar 1
:no-display-if (not telega-user-show-avatars))
;; Setup `off-column' for "invited by" string
(setq off-column (telega-current-column))
(telega-ins--user-status user)
(when-let ((join-date (plist-get member :joined_chat_date)))
(unless (zerop join-date)
(telega-ins ", joined ")
(telega-ins--date join-date)))
(telega-ins-prefix ", "
(telega-ins--user-nearby-distance user))
(when-let* ((inviter-id (plist-get member :inviter_user_id))
(inviter-user (unless (zerop inviter-id)
(telega-user-get inviter-id 'local))))
(telega-ins "\n")
(telega-ins (make-string off-column ?\s))
(telega-ins "invited by ")
(telega-ins--raw-button (telega-link-props 'user inviter-id 'type 'telega)
(telega-ins--msg-sender inviter-user :with-avatar-p t)))
t))
(defun telega-ins--message0 (msg &optional no-header
addon-header-inserter no-footer)
"Insert message MSG.
If NO-HEADER is non-nil, then do not display message header
unless message is edited.
ADDON-HEADER-INSERTER is passed directly to `telega-ins--message-header'."
(declare (indent 2))
(if (telega-msg-special-p msg)
(telega-ins--with-attrs (list :min (- telega-chat-fill-column
(telega-current-column))
:align 'center
:align-symbol 'horizontal-bar)
(telega-ins--content msg))
;; Message header needed
(let* ((chat (telega-msg-chat msg))
;; Is formatting done for "Replies" chat?
;; Workaround for case when `:forward_info' is unset (for
;; outgoing messages [what?] for example)
(msg-for-replies-p (and (telega-replies-p chat)
(plist-get msg :forward_info)))
(sender (if msg-for-replies-p
(telega-replies-msg-sender msg)
(telega-msg-sender msg)))
(sender-name (if (telega-user-p sender)
(telega-user-title sender 'full-name)
(cl-assert (telega-chat-p sender))
(telega-chat-title sender)))
(avatar (if msg-for-replies-p
(telega-msg-sender-avatar-image-three-lines sender)
(telega-msg-sender-avatar-image sender)))
(awidth (length (telega-image--telega-text avatar 0)))
;; NOTE: `telega-msg-contains-unread-mention' is used
;; inside `telega--entity-to-properties'
(telega-msg-contains-unread-mention
(plist-get msg :contains_unread_mention))
ccol)
(if (and no-header
(zerop (plist-get msg :edit_date))
(zerop (plist-get msg :via_bot_user_id)))
(telega-ins (make-string awidth ?\s))
;; Show user profile when clicked on avatar, header
(telega-ins--with-props
(list 'action (lambda (button)
;; NOTE: check for custom message :action first
;; - [RESEND] button uses :action
;; - via @bot link uses :action
(or (telega-button--action button)
(telega-describe-msg-sender sender))))
(telega-ins--image avatar 0
:image-ascent (telega-ins--ascent-percent sender-name)
:no-display-if (not telega-chat-show-avatars))
(telega-ins--message-header msg chat sender addon-header-inserter)
(telega-ins--image avatar 1
:image-raise telega-avatar-slice-2-raise
:no-display-if (not telega-chat-show-avatars))))
(setq ccol (telega-current-column))
(telega-ins--fwd-info-inline (plist-get msg :forward_info))
;; NOTE: Three lines avatars in "Replies" chat
(when msg-for-replies-p
(telega-ins--image avatar 2
:no-display-if (not telega-chat-show-avatars)))
(when (< (telega-current-column) ccol)
(telega-ins--move-to-column ccol))
(when (< (telega-current-column) ccol)
(telega-ins--move-to-column ccol))
(telega-ins--msg-reply-inline msg)
(telega-ins--column ccol telega-chat-fill-column
(telega-ins--content msg)
(telega-ins-prefix "\n"
(telega-ins--msg-sending-state-failed msg))
(when (telega-msg-match-p msg telega-msg-temex-show-reactions)
(telega-ins-prefix "\n"
(telega-ins--msg-reaction-list msg)))
(telega-ins-prefix "\n"
(telega-ins--reply-markup msg))
(telega-ins-prefix "\n"
(telega-ins--msg-comments msg chat))
)))
(unless no-footer
;; Footer: Date/status starts at `telega-chat-fill-column' column
(telega-ins--move-to-column telega-chat-fill-column)
(telega-ins--with-attrs (list :align 'right :min 10)
;; NOTE: telegaInternal messages has no `:date' property
(when-let ((date (or (telega--tl-get msg :scheduling_state :send_date)
(plist-get msg :date))))
(telega-ins--date date)))
(telega-ins--outgoing-status msg))
t)