Skip to content

Releases: ChuYanLon/telegram.nvim

v0.7.1

Choose a tag to compare

@ChuYanLon ChuYanLon released this 29 Jul 06:41

Added

  • blink.cmp source — full completion source for telegram buffers: emoji (:name), @mentions with async member fetch, bot commands (/cmd), code block languages (```lang)
  • Polls — create (@createpoll), vote (@vote), view voters (@voters), stop (@stoppoll); supports multi-answer, timed polls
  • Rich text highlights — bold, italic, code, strikethrough, spoiler, link text with dedicated highlight groups
  • 15+ new service message types — contacts, venues, locations, stories, boosts, payments, gifts, giveaways, stake dice, TON, etc.
  • Translation — @translate / @translate_zh with floating window display
  • Jump to date — @jump_to_date supports YYYY-MM-DD, today, yesterday
  • Profile management — @myprofile view/edit name and bio
  • Contacts browsing — @contacts list and DM contacts
  • Join request management — @joinrequests approve/decline pending requests
  • Admin event log — @eventlog browse recent admin actions
  • Shared chat/user opener — @openshared for shared chats/users from messages
  • @-less mention — mention members without @username via textEntityTypeMentionName
  • Link previews — structured multi-line display with site info
  • Docs automation — tools table and feature sections auto-generated from Lua source

Fixed

  • blink scan loop — / trigger in get_trigger_characters() but not get_completions() fixed
  • blink member dedup/cache/async guards — stale data, duplicate items, permanent fetch lock all fixed
  • blink registration — use add_filetype_source() public API instead of config mutation
  • Poll stop/vote/error handling — reply_markup removed from stopPoll payload, sendPoll returns errors
  • Link preview, profile fetch, server JSON null, timer leaks — various crash/behavior fixes

Changed

  • blink trigger — bot commands moved from ! to / (standard Telegram prefix)
  • translate_zh default key — z → tt
  • Poll V keymap — removed, use @vote instead
  • Performance — message window capped at 200, curl timeouts reduced, exit freeze fixed

v0.7.0

Choose a tag to compare

@ChuYanLon ChuYanLon released this 27 Jul 02:38

Features

  • Chat folders — browse Telegram folders with dedicated picker, async chat loading
  • Forward with reply context — new F key preserves reply chains when forwarding
  • Deleted message tombstoning — messages show "[Message deleted]" instead of disappearing

UI / Docs Site

  • Docs site redesigned with Astro-inspired dark theme, responsive layout
  • Dark / light / auto theme toggle
  • Prism syntax highlighting for code blocks
  • Copy button on code blocks
  • Self-hosted fonts (removed external CDN dependency)

Docs Automation

  • pnpm gen:docs — auto-generates keymaps table from config.lua into README + wiki pages
  • CI auto-fixes stale docs and syncs to GitHub Wiki on push to main
  • CLAUDE.md added for AI-assisted development
  • README feature checklist simplified to high-level categories

Bug Fixes

  • Timer crash on destroy — graceful pcall wrap for vim.fn.timer_stop
  • Chat folder name parsing — fix nested text field access
  • Deleted message rendering — render placeholder instead of crash

Security

  • Express 4 → 5 migration
  • ws 8.21.1, vite 7.3.5, esbuild 0.28.1 — all Dependabot alerts patched
  • pnpm.overrides pins transitive deps to secure versions

Chores

  • Bumped all dependencies to latest compatible versions
  • Removed redundant folder notifications

v0.6.0

Choose a tag to compare

@ChuYanLon ChuYanLon released this 08 Jun 02:09

What's new

  • Input editor redesign — bottom-panel style with context preview for reply/edit modes; markdown syntax highlighting while typing
  • Connection status indicator — title bar shows red dot when TDLib reports disconnected/connecting state
  • Link previews — messages with URLs show [site — title](url) preview below the link
  • Forwarded from label — forwarded messages show ↳ name above the content
  • Edited indicator — edited messages show [edited] in the message footer alongside views and reactions; editDate field propagated through TypeScript backend and Lua state
  • Copy message text — press yy in the chat window to copy the current message's text to the system clipboard
  • Favorites (Saved Messages) — dedicated chat always present in group list with 📌 icon; press s to forward current message to Favorites with confirmation dialog
  • View counts — channel messages show 👀 N footer with k/M formatting; real-time sync via updateMessageInteractionInfo WebSocket event
  • Read receipts — outgoing private messages display (read HH:MM) in header when recipient has read the message; uses getMessageReadDate + updateMessageReadDate real-time updates
  • Configurable panel position — panel_position option supports "right" (default), "left", "bottom", "top"

Fixed

  • Message object field preservation — views, readDate, reactions, editDate now stored on new message objects in Lua state
  • Favorites chat identification — isSaved flag replaces existing chat entry in list instead of duplicating
  • Favorites notifications — messages in Favorites chat excluded from should_notify() via saved_chat_id
  • Cursor positioning on empty chat — set_cursor_to_idx guards against nil message when target index is out of bounds

v0.5.4

Choose a tag to compare

@ChuYanLon ChuYanLon released this 05 Jun 06:53

What's new

  • Loading indicators and empty state — chat buffer shows loading spinner during fetch and "No messages" when empty
  • Date separators and unread divider — date group headers between messages; "Unread messages" divider at the unread boundary
  • Unread-aware loading — initial load fetches 30 messages (up from 10), centered around lastReadInboxMessageId

Fixed

  • Cursor positioned at first unread message — jumps to first message below the unread divider, not date group boundary
  • Unread divider stays fixed — stays at original position until all messages above are read; per-message read tracking
  • Read receipt reliability — last_read_id persisted per-chat like saved_cursors, protected from stale server responses; read only marked when cursor reaches last line of a message
  • Unread count accuracy — deduplicated load_newer counting; own/at-bottom messages no longer increment; math.min() guards against stale server counts
  • Cursor maintenance — tracked by message ID during older loads, not buffer line number
  • extra_before delta — corrected cumulative offset calc using (extra - prev_extra) in incremental loops
  • Immediate title/status update — CursorMoved calls update_title() + redrawstatus right after marking read, no longer waiting for server round-trip

Changed

  • Initial message load — 10 → 30 messages on first chat open
  • getChat returns lastReadInboxMessageId — Lua side receives it for unread-aware positioning

v0.5.3

Choose a tag to compare

@ChuYanLon ChuYanLon released this 04 Jun 08:10

What's new

  • Message reactions — press r on a message to open the emoji picker (40+ verified emojis); same emoji toggles off, different auto-switches; real-time sync via WebSocket
  • Admin custom titles — shows custom titles next to admin names in messages and member list
  • Unread count in lualine — require("telegram").lualine shows unread badge and @mention indicators with color-coded status
  • Configurable notification types — notify_chat_types setting to control which chats trigger desktop notifications
  • HD media auto-download — @refreshmedia downloads highest-quality photos/videos under cursor

Fixed

  • Unread count double-counting — chatReadInbox (TDLib authoritative count) now correctly overrides local increment. Status bar refreshes immediately when count changes.
  • Stale unread_mention_count — ignored when unread_count is 0
  • Sticker auto-download — prefers high-quality mediaPath over thumbnail
  • Service messages no longer trigger media download
  • mention_count reset — cleared when opening chat or scrolling past unread messages
  • last_msg preserved — across group list refreshes

Refactor

  • ui.lua split — dedicated modules: state, groups, reactions, editor, help, title

v0.5.2

Choose a tag to compare

@github-actions github-actions released this 03 Jun 04:01

[0.5.2] - 2026-06-03

Performance

  • Message window capped at 200 — state.messages no longer grows unbounded; trimmed on scroll and new message arrival to prevent long-session lag
  • CursorMoved handler debounced — O(n) message scan and pagination trigger deferred to 50ms after last cursor movement, eliminating jank on rapid scrolling
  • curl_with_retry timeouts reduced — retries 4→2, max-time 15s→5s, connect-timeout 5s→2s for faster failure recovery
  • Chat title update debounced — VimResized/WinScrolled no longer share the same augroup (VimResized was silently dropped)
  • close_chat non-blocking — replaced synchronous vim.fn.system("curl") with fire-and-forget request_async, preventing exit freeze
  • Timer leaks fixed — refresh_timer, _scroll_timer, _typing_timer, _title_update_timer now properly stopped in destroy_chat, logout, and VimLeavePre
  • _edit_ts stale entries cleaned — expired edit debounce timestamps removed on each new edit

Caching

  • _users cache — capped at 5,000 entries with gentle FIFO eviction; updated in real-time via updateUser events
  • _chats cache — capped at 500 entries; new chats from updateNewChat evict oldest when full; individual chat inserts use _cacheChat
  • _pinnedMessageIds cache — capped at 200 entries; pin/unpin events update cache; unpin removes entry

Fixed

  • Exit freeze on Neovim close — server now exits immediately on SIGTERM (without awaiting TDLib close), Neovim doesn't wait for the job
  • First-exit lag — TDLib's first-time database finalization no longer blocks Neovim's shutdown
  • Remote session termination — updateAuthorizationState (closed/logging-out) clears all caches and notifies Lua UI
  • Stale typing indicators — typing_users entries for the previous chat are cleaned up on open_chat switch

Changed

  • SIGTERM exits immediately — closes HTTP/WS servers and calls process.exit(0) without tgClient.shutdown(); SIGINT (Ctrl+C) still does graceful shutdown
  • getGroups() always fetches fresh — reverted to getChats(true) to avoid stale chat list when chats are removed

[0.5.0] - 2026-06-01

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 02 Jun 09:43

[0.5.0] - 2026-06-01

Added

  • Customizable keymaps — all 21 keymaps configurable via setup({ keys = { ... } }); set to false to disable
  • Theme-adaptive highlights — all highlight groups derive from Neovim theme (Comment, DiffAdd, DiagnosticOk, etc.) with no hardcoded colors
  • Granular default permissions editor — interactive floating window with 14 permission toggles, toggle-all switch, color-coded highlights for enabled/disabled/unknown states
  • Edit invite links — frontend wrapper and UI entry for editing invite links (member limit + expiration)
  • Expiration support for invite links — create/edit invite links with optional expiry time
  • @username search for adding members — search by username instead of raw numeric user ID
  • Invite link fallback — when adding a member to a supergroup fails, the invite link is returned to the user instead of a generic error
  • Member list includes admins and creator — dual-filter search merges chatMembersFilterAdministrators and chatMembersFilterMembers
  • WebSocket sync for chat metadata — user name changes, online/offline status, group description/member count, group kicked/banned now sync in real-time from other clients
  • Online status — user is marked as online after login with periodic heartbeat (30s), visible to other clients
  • Device model — session shows as telegram.nvim (with version and OS) in Telegram device list
  • Defensive error guards — getChatInviteLinks handles getMe() failure; handleChatMemberUpdate guards undefined user IDs; SIGTERM now does graceful shutdown

Fixed

  • Channel unsubscribe now actually leaves — changed from deleteChatHistory to leaveChat
  • restrictChatMember/unrestrictChatMember not working — used wrong TDLib field can_send_messages instead of can_send_basic_messages
  • Member actions shown regardless of status — Ban/Unban/Restrict/Promote now dynamically shown based on member's current status
  • promoteChatMember grants can_promote_members — removed to prevent privilege escalation
  • Title float covering messages — buffer padding now syncs with float height on every update_title() call, preventing overlap (#123)
  • Cursor move freeze — msg_line_counts cache eliminates #fmt_msg() re-render on every cursor movement
  • WinScrolled storm — debounced update_title() calls (100ms) reduce float recreation overhead on scroll
  • User name not updating in rendered messages — on userUpdate, sender names in existing messages are refreshed via render()
  • ChatPosition event name mismatch — migrated from broadcastRaw (uppercase) to explicit lowercase handler
  • truncate_text negative width — pinned message/description titles no longer break at narrow window widths

Changed

  • Removed nui.nvim dependency — help popup and input editor migrated from nui.popup to built-in nvim_open_win
  • request_async — restored to prefer vim.net.request with curl fallback (reverted experimental change)
  • set_groups — now stores user_id for private chat lookups

What's Changed

  • chore(deps-dev): bump tsx from 4.22.3 to 4.22.4 by @dependabot[bot] in #128

New Contributors

Full Changelog: v0.5.0...v0.5.1

v0.5.0

Choose a tag to compare

@ChuYanLon ChuYanLon released this 01 Jun 09:20

[0.5.0] - 2026-06-01

Added

  • Customizable keymaps — all 21 keymaps configurable via setup({ keys = { ... } }); set to false to disable
  • Theme-adaptive highlights — all highlight groups derive from Neovim theme (Comment, DiffAdd, DiagnosticOk, etc.) with no hardcoded colors
  • Granular default permissions editor — interactive floating window with 14 permission toggles, toggle-all switch, color-coded highlights for enabled/disabled/unknown states
  • Edit invite links — frontend wrapper and UI entry for editing invite links (member limit + expiration)
  • Expiration support for invite links — create/edit invite links with optional expiry time
  • @username search for adding members — search by username instead of raw numeric user ID
  • Invite link fallback — when adding a member to a supergroup fails, the invite link is returned to the user instead of a generic error
  • Member list includes admins and creator — dual-filter search merges chatMembersFilterAdministrators and chatMembersFilterMembers
  • WebSocket sync for chat metadata — user name changes, online/offline status, group description/member count, group kicked/banned now sync in real-time from other clients
  • Online status — user is marked as online after login with periodic heartbeat (30s), visible to other clients
  • Device model — session shows as telegram.nvim (with version and OS) in Telegram device list
  • Defensive error guards — getChatInviteLinks handles getMe() failure; handleChatMemberUpdate guards undefined user IDs; SIGTERM now does graceful shutdown

Fixed

  • Channel unsubscribe now actually leaves — changed from deleteChatHistory to leaveChat
  • restrictChatMember/unrestrictChatMember not working — used wrong TDLib field can_send_messages instead of can_send_basic_messages
  • Member actions shown regardless of status — Ban/Unban/Restrict/Promote now dynamically shown based on member's current status
  • promoteChatMember grants can_promote_members — removed to prevent privilege escalation
  • Title float covering messages — buffer padding now syncs with float height on every update_title() call, preventing overlap (#123)
  • Cursor move freeze — msg_line_counts cache eliminates #fmt_msg() re-render on every cursor movement
  • WinScrolled storm — debounced update_title() calls (100ms) reduce float recreation overhead on scroll
  • User name not updating in rendered messages — on userUpdate, sender names in existing messages are refreshed via render()
  • ChatPosition event name mismatch — migrated from broadcastRaw (uppercase) to explicit lowercase handler
  • truncate_text negative width — pinned message/description titles no longer break at narrow window widths

Changed

  • Removed nui.nvim dependency — help popup and input editor migrated from nui.popup to built-in nvim_open_win
  • request_async — restored to prefer vim.net.request with curl fallback (reverted experimental change)
  • set_groups — now stores user_id for private chat lookups

What's Changed

  • feat: channel support, group management, async search, vim.net.request by @ChuYanLon in #127

Full Changelog: v0.4.1...v0.5.0

v0.4.1

Choose a tag to compare

@ChuYanLon ChuYanLon released this 29 May 07:45

[0.4.0] - 2026-05-28

Added

  • :TgPr squash merge — now offers "squash" and "commit" merge strategies when merging PRs
  • Private chat support — press c on a message to open DM with sender; @newchat tool to start DM by @username
  • Snacks picker — chat picker now uses snacks.nvim with fuzzy search, falls back to vim.ui.select
  • Confirmation prompt before opening DM — vim.ui.select asks Yes/No before opening a private chat
  • ImageMagick requirement — documented in README for image display in Kitty terminal

Changed

  • Updated all documentation — CONTRIBUTING, WORKFLOW, wiki pages, PR template, and CHANGELOG synced with current TypeScript architecture and feature set
  • Terminology — user-facing text unified to use "chat" instead of "group" (picker, help popup, notifications)
  • Online count — now fetched synchronously from TDLib on chat open with cache fallback; stale 0 values from WebSocket ignored
  • Typing indicator — shown in a floating popup below the winbar instead of replacing the title bar
  • Service message prefixes — changed from markdown-significant characters (+, -, *, >) to bracket format ([+], [-], [*], [>])
  • README screenshots — reorganized with new screenshot categories and Image Preview section

Fixed

  • Service message highlighting — added TgService highlight group for service messages
  • Wiki sync workflow — pull rebase before push to avoid push conflicts
  • Online count - stale 0 values from WebSocket no longer overwrite cached counts

Full Changelog: v0.4.0...v0.4.1

v0.4.0

Choose a tag to compare

@ChuYanLon ChuYanLon released this 29 May 02:44

[0.4.0] - 2026-05-29

Added

  • Missing TDLib update handlers — message edits, deletions, group list, unread sync now broadcast via WebSocket in real-time
  • Graceful shutdown — SIGINT handler closes TDLib/WebSocket/HTTP properly, preventing binlog corruption
  • Date-based pagination — load_older/load_newer use message.date instead of message.id, fixing wrong messages loading in migrated groups
  • Login timeout — 5-minute timeout for TDLib login to prevent hanging forever
  • getChats iteration limit — max 1000 loops to prevent infinite pagination
  • Server route tests — expanded from 1 to 17 tests covering all endpoints
  • :TgPr squash merge — now offers squash and commit merge strategies
  • Private chat support — press c on a message to open DM; @newchat tool to DM by @username
  • Snacks picker — chat picker uses snacks.nvim with fuzzy search, falls back to vim.ui.select
  • ImageMagick requirement — documented for image display in Kitty terminal

Changed

  • GitHub ops extracted — :TgPr and :TgIssue moved to lua/telegram/github.lua, reducing init.lua by 370 lines
  • Updated all documentation — wiki pages synced with current architecture and features
  • Online count — fetched synchronously from TDLib with cache fallback
  • Typing indicator — floating popup below winbar instead of replacing title bar
  • Service message prefixes — bracket format ([+], [-], etc.) for safety
  • Console logging added — console.warn in all empty catch blocks for debuggability

Fixed

  • Inconsistent chatId type conversion — normalized across all API endpoints (#113 by @jaideepkathiresan)
  • Auth race condition — wait for server ack before re-prompting auth input
  • TDLib version parsing — regex handles pre-release tags like 1.8.64-beta
  • JSON null safety — LuaJIT cdata handling for chatLastMessageUpdated event
  • Service message highlighting — TgService highlight group
  • Wiki sync workflow — pull before commit to avoid push conflicts
  • Online count — stale 0 values from WebSocket no longer overwrite cached counts

Docs

  • README — remove groups sidebar item, add ImageMagick requirement, reorganize screenshots (#115 by @ChuYanLon)
  • Group management — split into separate todo items (#112 by @ChuYanLon)
  • Wiki — synced with v0.4.0 architecture and features