Skip to content

新增訊息閱讀器功能 (NVDA+Windows+J)#47

Merged
keyang556 merged 13 commits intomainfrom
claude/gracious-wright
Apr 9, 2026
Merged

新增訊息閱讀器功能 (NVDA+Windows+J)#47
keyang556 merged 13 commits intomainfrom
claude/gracious-wright

Conversation

@keyang556
Copy link
Copy Markdown
Owner

@keyang556 keyang556 commented Apr 8, 2026

Summary

  • NVDA+Windows+J 快捷鍵:自動點擊「更多選項」→ 自動點擊「儲存聊天」→ 自動儲存至附加元件暫存資料夾 → 開啟訊息閱讀器
  • 重用現有 _activateMoreOptionsMenu + ChatMoreOptions 虛擬視窗邏輯,確保點擊位置與 NVDA+Windows+O 完全相同
  • 訊息閱讀器:上/下方向鍵逐則切換,每則格式為「姓名 訊息內容 時間」,自動語音朗讀

New Files

  • addon/appModules/_chatParser.py — 解析 LINE 聊天匯出 .txt 格式(支援一般訊息、收回訊息,跳過日期行)
  • addon/appModules/_messageReader.py — wx 訊息閱讀器對話框

Changes

  • addon/appModules/line.py — 新增 script_openMessageReader_messageReaderAutoClickSaveChat_messageReaderHandleSaveDialog_findSaveDialogEditEnumChildWindows 遞迴搜尋)、_messageReaderPressSaveBM_CLICK 點擊存檔按鈕)、_messageReaderHandleOverwrite_messageReaderOpenFile;修改 _handleChatMoreOptionsAction 以支援訊息閱讀器流程
  • addon/globalPlugins/lineDesktopHelper.py — 新增 NVDA+Windows+J 快捷鍵、工具選單「訊息閱讀器」項目

Test plan

  • 開啟 LINE 聊天室,按 NVDA+Windows+J,確認自動儲存並開啟訊息閱讀器視窗
  • 訊息閱讀器中按上/下方向鍵,確認逐則朗讀「姓名 內容 時間」
  • 確認 NVDA+Windows+O(更多選項)功能不受影響
  • 確認工具選單中出現「訊息閱讀器」項目

🤖 Generated with Claude Code

Greptile Summary

此 PR 新增了「訊息閱讀器」功能(NVDA+Windows+J),讓使用者可自動儲存 LINE 聊天紀錄並透過鍵盤逐則瀏覽與朗讀訊息。主要新增 _chatParser.py(聊天匯出解析)、_messageReader.py(wx 對話框),並在 line.py 加入自動化點擊流程、在 lineDesktopHelper.py 加入快捷鍵與選單項目。

  • 相比上一輪審查,本 PR 已解決大部分關鍵問題:多行訊息合併、單例防護、關閉後 RuntimeError、暫存檔案清理、_messageReaderPending 旗標提前清除等
  • _messageReaderHandleSaveDialog 函式中存在兩個 import tempfile 語句,第一個(函式頂部)是冗餘的重複匯入
  • _messageReaderHandleOverwrite 重試次數耗盡且仍有對話框時,_messageReaderPending 旗標不會被清除,且不呼叫 _messageReaderOpenFile(前次審查已指出,此次仍未修正)

Confidence Score: 4/5

此 PR 大幅改善,前次審查的主要問題多已解決,整體可安全合併

前次審查的關鍵問題(多行訊息、單例防護、RuntimeError、暫存檔清理、旗標提前清除、並發保護)均已妥善處理。剩餘的 _messageReaderHandleOverwrite 重試耗盡後不清除 _messageReaderPending 及不通知使用者的問題是邊緣案例(需要連續 6 次重試都失敗),對主要功能路徑影響有限。冗餘 import tempfile 僅為風格問題,不影響執行。

重點關注 addon/appModules/line.py_messageReaderHandleOverwrite 函式(重試耗盡後的錯誤處理路徑)

Vulnerabilities

  • 聊天匯出暫存檔案(lineDesktop_chat_export.txt)現已在對話框關閉時透過 cleanupPath 機制刪除,已解決前次的持久化隱私問題
  • 仍使用可預測固定檔名,但因已有清理機制,風險大幅降低
  • _messageReaderHandleOverwrite 向 LINE 處理序對話框送出 Enter 鍵,若重試期間 LINE 恰好彈出其他 #32770 對話框(如錯誤訊息),仍可能被誤關閉(前次審查已指出)

Important Files Changed

Filename Overview
addon/appModules/_chatParser.py 新增聊天匯出解析器;已加入多行訊息接續邏輯,_RECALL_RE 分隔符問題待確認實際匯出格式
addon/appModules/_messageReader.py 訊息閱讀器 wx 對話框;已加入單例防護與關閉後清理,邏輯清晰無明顯問題
addon/appModules/line.py 加入自動化儲存流程;_messageReaderHandleSaveDialog 有冗餘 import tempfile;重試耗盡後 _messageReaderPending 未清除的問題仍存在
addon/globalPlugins/lineDesktopHelper.py 新增 NVDA+Windows+J 快捷鍵與選單項目,結構與現有程式碼一致

Sequence Diagram

sequenceDiagram
    participant User as 使用者
    participant GP as GlobalPlugin
    participant AM as AppModule
    participant LINE as LINE 應用程式
    participant Parser as _chatParser.py
    participant Reader as _messageReader.py

    User->>GP: NVDA+Windows+J
    GP->>AM: script_openMessageReader(gesture)
    AM->>AM: 設定 _messageReaderPending = True
    AM->>LINE: _clickMoreOptionsButton()
    AM->>AM: callLater → _activateMoreOptionsMenu()
    AM->>AM: callLater → _messageReaderAutoClickSaveChat()
    AM->>LINE: 自動點擊「儲存聊天」
    LINE->>AM: _handleChatMoreOptionsAction
    AM->>AM: callLater → _messageReaderHandleSaveDialog()
    AM->>LINE: EnumWindows 找儲存對話框
    AM->>LINE: WM_SETTEXT 設定檔名路徑
    AM->>LINE: 點擊存檔按鈕 (BM_CLICK)
    LINE-->>AM: 儲存完成
    AM->>AM: callLater → _messageReaderHandleOverwrite()
    AM->>AM: callLater → _messageReaderOpenFile()
    AM->>Parser: parseChatFile(savePath)
    Parser-->>AM: messages[]
    AM->>Reader: openMessageReader(messages, cleanupPath)
    Reader-->>User: 顯示訊息閱讀器對話框
    User->>Reader: 方向鍵瀏覽訊息
    Reader->>Reader: speech.speakMessage(text)
    User->>Reader: 關閉
    Reader->>Reader: os.remove(cleanupPath)
Loading

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: addon/appModules/line.py
Line: 5942

Comment:
**`_messageReaderHandleSaveDialog` 中有兩個 `import tempfile`**

此函式在頂部已有一次 `import tempfile`,但後續(於實際使用前)又重複匯入一次。在 Python 中重複匯入同一模組雖然無害(會回傳快取的模組物件),但屬於冗餘程式碼,建議移除函式開頭那一行,保留靠近使用點的匯入即可。

(移除函式頂部的 `import tempfile`,保留此處即可)

How can I resolve this? If you propose a fix, please make it concise.

Reviews (11): Last reviewed commit: "Update addon/appModules/line.py" | Re-trigger Greptile

- NVDA+Windows+J 自動點擊更多選項 → 儲存聊天 → 解析聊天記錄 → 開啟訊息閱讀器
- 重用現有 _activateMoreOptionsMenu + ChatMoreOptions 虛擬視窗,確保點擊位置正確
- 新增 _chatParser.py:解析 LINE 聊天匯出格式(時間、姓名、內容,支援收回訊息)
- 新增 _messageReader.py:wx 對話框,上/下方向鍵逐則閱讀,格式為「姓名 內容 時間」
- 自動操作存檔對話框:以 EnumChildWindows 遞迴找到 Edit 控制項並設定暫存路徑
- 以 BM_CLICK 點擊存檔按鈕,更可靠地觸發儲存動作
- 在 NVDA 工具 > LINE Desktop 選單新增「訊息閱讀器」項目

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai

Comment on lines +3 to +5
_DATE_RE = re.compile(r'^\d{4}\.\d{2}\.\d{2} .+$')
_MSG_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?) (.+)$')
_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?)已收回訊息$')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 正規表示式假設欄位以空白分隔,但 LINE 匯出可能使用 Tab

LINE 桌面版的聊天記錄匯出格式通常以 Tab(\t 分隔時間、名稱與訊息內容,例如:

14:30	王小明	你好
14:31	李美華	已收回訊息

目前 _MSG_RE_RECALL_RE 皆以空白(' ')作為欄位分隔符號。若匯出格式確為 Tab 分隔,這兩個 regex 將無法正確解析任何訊息,導致 parseChatFile 永遠回傳空列表,使用者只會看到「聊天紀錄中沒有訊息」。

建議確認實際匯出格式後,視需要將空白改為 \t

_MSG_RE = re.compile(r'^(\d{2}:\d{2})\t(\S.+?)\t(.+)$')
_RECALL_RE = re.compile(r'^(\d{2}:\d{2})\t(\S.+?)\t已收回訊息$')

另外,若使用空白分隔,含有空白的使用者名稱(如 John Smith)只會將第一個詞解析為名稱,其餘詞彙會被歸入訊息內容,導致顯示錯誤。

Prompt To Fix With AI
This is a comment left during a code review.
Path: addon/appModules/_chatParser.py
Line: 3-5

Comment:
**正規表示式假設欄位以空白分隔,但 LINE 匯出可能使用 Tab**

LINE 桌面版的聊天記錄匯出格式通常以 **Tab(`\t`** 分隔時間、名稱與訊息內容,例如:

```
14:30	王小明	你好
14:31	李美華	已收回訊息
```

目前 `_MSG_RE``_RECALL_RE` 皆以空白(`' '`)作為欄位分隔符號。若匯出格式確為 Tab 分隔,這兩個 regex 將無法正確解析任何訊息,導致 `parseChatFile` 永遠回傳空列表,使用者只會看到「聊天紀錄中沒有訊息」。

建議確認實際匯出格式後,視需要將空白改為 `\t````python
_MSG_RE = re.compile(r'^(\d{2}:\d{2})\t(\S.+?)\t(.+)$')
_RECALL_RE = re.compile(r'^(\d{2}:\d{2})\t(\S.+?)\t已收回訊息$')
```

另外,若使用空白分隔,含有空白的使用者名稱(如 `John Smith`)只會將第一個詞解析為名稱,其餘詞彙會被歸入訊息內容,導致顯示錯誤。

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 目前匯出訊息實際格視為 11:29 可揚🇹🇼 有

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

確認格式是空白分隔(不是 Tab),現有的 _MSG_RE 正規表示式應該可以正確解析這個格式。

不過多行訊息問題仍需處理:如果使用者以 Shift+Enter 換行,後續行會被丟棄。建議在 parseChatFile 加入接續行累積邏輯:

def parseChatFile(filePath):
	messages = []
	with open(filePath, 'r', encoding='utf-8') as f:
		for line in f:
			line = line.rstrip('\r\n')
			if not line:
				continue
			if _DATE_RE.match(line):
				continue
			m = _RECALL_RE.match(line)
			if m:
				messages.append({
					'time': m.group(1),
					'name': m.group(2),
					'content': '已收回訊息',
				})
				continue
			m = _MSG_RE.match(line)
			if m:
				messages.append({
					'time': m.group(1),
					'name': m.group(2),
					'content': m.group(3),
				})
				continue
			# Continuation line: append to last message
			if messages:
				messages[-1]['content'] += '\n' + line
	return messages

Tip: You can customize Greptile's behavior for this repo with .greptile/rules and .greptile/config.

接續行(不符合日期/訊息格式的行)累積至上一則訊息的 content。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

Tip:

Greploops — Automatically fix all review issues by running /greploops in Claude Code. It iterates: fix, push, re-review, repeat until 5/5 confidence.

Use the Greptile plugin for Claude Code to query reviews, search comments, and manage custom context directly from your terminal.

將聊天匯出暫存檔從插件目錄內 (addons/lineDesktop/temp/) 改為
系統暫存目錄 (%TEMP%/lineDesktop_chat_export.txt),
防止 NVDA 更新插件時因資料夾被鎖定而發生 PermissionError (WinError 5)。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 這樣可以嗎?

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

還不行,兩個關鍵問題都未修正:

1. 多重對話框問題 (_messageReader.py:113-119)
openMessageReader 仍然每次都建立新對話框,快速按兩次 NVDA+Windows+J 會堆疊多個視窗並同時朗讀。

2. 誤觸其他對話框 (line.py:6087-6109)
_messageReaderHandleOverwrite 找到 LINE 任何 #32770 對話框就送 Enter,可能誤觸更新通知等無關視窗。

建議修正:

修正 1 - 防止多重對話框:

# _messageReader.py 開頭新增
_readerDialog = None

def openMessageReader(messages, title="訊息閱讀器"):
    def _show():
        global _readerDialog
        if _readerDialog is not None:
            try:
                _readerDialog.Raise()
                _readerDialog.SetFocus()
                return
            except Exception:
                _readerDialog = None
        _readerDialog = MessageReaderDialog(messages, title=title)
        _readerDialog.Show()
        _readerDialog.Raise()
    wx.CallAfter(_show)

並在 MessageReaderDialog._onClose 清除:

def _onClose(self, evt):
    global _readerDialog
    _readerDialog = None
    self.Destroy()

修正 2 - 驗證對話框標題:
_messageReaderHandleOverwrite 中送 Enter 前檢查標題:

if dialogHwnd:
    # 驗證是否為覆寫確認框
    textBuf = ctypes.create_unicode_buffer(512)
    ctypes.windll.user32.GetWindowTextW(dialogHwnd, textBuf, 512)
    dialogText = textBuf.value
    OVERWRITE_KEYWORDS = ("覆寫", "取代", "已存在", "overwrite", "replace", "already exists")
    if not any(kw.lower() in dialogText.lower() for kw in OVERWRITE_KEYWORDS):
        # 不是覆寫確認框,直接開啟檔案
        core.callLater(300, self._messageReaderOpenFile)
        return
    # 是覆寫確認框,送 Enter
    # ... 現有的 SendMessageW 程式碼

修正後再測試即可合併。

keyang556 and others added 2 commits April 9, 2026 07:27
新增 cleanupPath 參數到訊息閱讀器,當對話框關閉時
自動刪除 %TEMP% 中的聊天匯出暫存檔,避免累積臨時檔案。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
在設定存檔路徑前先刪除已存在的 lineDesktop_chat_export.txt,
讓 LINE 的另存新檔對話框不會出現「是否取代」確認視窗。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 這樣可以嗎?

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

對,這三個建議都可以解決對應的問題:

  1. 並發保護 - 加入 _messageReaderPending 檢查可以防止重複觸發時覆寫共享狀態
  2. 起始位置 - 改成 self._pos = 0 讓使用者從第一則訊息開始閱讀更符合直覺
  3. Escape 處理 - 移除 _onKeyDown 中的 Escape 處理避免重複呼叫 Close()

這些都是安全且直接的修正。

- script_openMessageReader 加入 _messageReaderPending 檢查,防止重複觸發時覆寫共享狀態
- 訊息起始位置改為第一則(pos=0),符合閱讀直覺
- 移除 _onKeyDown 中重複的 Escape 處理,統一交由 _onCharHook 負責

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 這樣可以嗎?

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

差不多了!兩個問題已完全解決,一個還需小改:

✓ Issue 2 (訊息閱讀器起始位置): 已修正為從第一則訊息開始 (self._pos = 0)

✓ Issue 3 (Escape 鍵重複處理): 已從 _onKeyDown 移除 Escape 處理,只保留在 _onCharHook

⚠️ Issue 1 (並發保護): 有加檢查但缺少使用者回饋。目前只是靜默 return,使用者重複按快捷鍵時不知道為什麼沒反應。建議改成:

if getattr(self, '_messageReaderPending', False):
    ui.message(_("訊息閱讀器正在執行中,請稍候"))
    return

加上這行提示,使用者體驗會更好。

keyang556 and others added 2 commits April 9, 2026 07:58
改為朗讀「訊息閱讀器正在執行中,請稍候」而非靜默返回。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
加入模組層級的 _readerDlg sentinel,若視窗已開啟則直接
Raise 聚焦而非再建立新的 MessageReaderDialog 實例。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 這樣可以嗎?

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

單例防護(Issue 2)已正確實作 ✓

你加入的程式碼:

_readerDlg = None  # module-level singleton sentinel

def openMessageReader(...):
    def _show():
        global _readerDlg
        if _readerDlg and _readerDlg.IsShown():
            _readerDlg.Raise()
            return
        _readerDlg = MessageReaderDialog(...)

這個實作是正確的!現在重複按 NVDA+Windows+J 只會聚焦到已開啟的視窗,而不會建立新視窗。


但是 Issue 1(翻譯字串)仍未修正:

以下字串仍然是硬編碼中文,沒有用 _() 包裹:

  • Line 55: "沒有訊息"
  • Line 97: "已經是第一則訊息"
  • Line 106: "已經是最後一則訊息"
  • Line 13, 123: title="訊息閱讀器"
  • Line 36: "關閉(&C)"

需要全部改成:

_("已經是第一則訊息")
_("已經是最後一則訊息")
_("沒有訊息")
title=_("訊息閱讀器")
_("關閉(&C)")

修正這些後就完全符合建議了。

所有 UI 字串(視窗標題、按鈕、提示訊息)改用 _() 包裹,
支援 NVDA 多語系翻譯機制。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 這樣可以嗎?

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

兩個問題都還沒修正 (both issues are still not fixed):

問題 1 (_messageReader.py:108-118):
_onClose 仍然沒有在 self.Destroy() 之前將 _readerDlg 重設為 None,關閉後再次開啟仍會導致 RuntimeError。

問題 2 (line.py:5885-5892):

  • _handleChatMoreOptionsAction 在第 5888 行仍然立即清除 self._messageReaderPending = False
  • _messageReaderOpenFile 結尾也沒有加上 self._messageReaderPending = False

需要修改:

  1. _messageReader.py_onClose 方法,在 self.Destroy() 前加一行:
_readerDlg = None  # Allow future invocations to create a new instance
  1. line.py
    • _handleChatMoreOptionsAction 移除第 5888 行的 self._messageReaderPending = False
    • _messageReaderOpenFile 的每個出口(所有 returnexcept 區塊最後)加上 self._messageReaderPending = False

keyang556 and others added 2 commits April 9, 2026 08:25
- _onClose 關閉前將 _readerDlg 重設為 None,避免持有已銷毀物件的 wrapper
- 移除 _handleChatMoreOptionsAction 中過早清除 _messageReaderPending 的程式碼
- 在 _messageReaderOpenFile 的所有出口(return 及 except)加上 _messageReaderPending = False

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
移除錯誤的 `from languageHandler import gettext as _`,
_() 已由 line.py 呼叫 addonHandler.initTranslation() 注入為 builtin,
子模組直接使用即可。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 這樣可以嗎?

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

抱歉,三個問題都還沒有修正:

1. _chatParser.py:5 仍然缺少空白:

# 現在(錯誤):
_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?)已收回訊息$')

# 應該是:
_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?) 已收回訊息$')
                                            # ↑ 這裡需要空白

2. line.py 兩處錯誤返回都沒有重設旗標:

第一處(約 5966 行):

else:
    self._messageReaderPending = False  # ← 加這行
    ui.message(_("未偵測到儲存對話框"))

第二處(約 5989 行):

if not editHwnd:
    self._messageReaderPending = False  # ← 加這行
    ui.message(_("無法操作儲存對話框"))

3. _findSaveDialogEdit 中的 WNDENUMPROC 仍使用 c_bool:

# 約 6012 行,改成:
WNDENUMPROC = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)

self._messageReaderPending = False 被意外寫成空格縮排,
導致 Python 解析失敗,改回正確的 tab 縮排。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 這樣可以嗎?

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

你嘗試修復了 Issue 3,但縮排有問題 — 第 5993 行用了 4 個空格,而後面兩行用了 tab。應該統一使用 tab:

	if not editHwnd:
		self._messageReaderPending = False
		ui.message(_("無法操作儲存對話框"))
		return

另外,Issue 1 和 Issue 2 仍未修復

  1. 第 5944 行的重複 import tempfile 仍需刪除
  2. 第 5969-5970 行仍需在 else: 區塊中加入 self._messageReaderPending = False


_DATE_RE = re.compile(r'^\d{4}\.\d{2}\.\d{2} .+$')
_MSG_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?) (.+)$')
_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?)已收回訊息$')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 _RECALL_RE 在訊息名稱與「已收回訊息」之間缺少空白

_MSG_RE 使用空白分隔三個欄位(時間、名稱、內容),格式為 HH:MM NAME content。但 _RECALL_RE 在名稱與「已收回訊息」之間沒有空白,格式為 HH:MM NAME已收回訊息

若 LINE 匯出格式為 HH:MM NAME 已收回訊息(名稱後有空白),_RECALL_RE 無法匹配,此行會進入 _MSG_RE 匹配,將「已收回訊息」視為普通訊息內容,失去語意標記。

建議修正為:

Suggested change
_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?)已收回訊息$')
_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?) 已收回訊息$')
Prompt To Fix With AI
This is a comment left during a code review.
Path: addon/appModules/_chatParser.py
Line: 5

Comment:
**`_RECALL_RE` 在訊息名稱與「已收回訊息」之間缺少空白**

`_MSG_RE` 使用空白分隔三個欄位(時間、名稱、內容),格式為 `HH:MM NAME content`。但 `_RECALL_RE` 在名稱與「已收回訊息」之間沒有空白,格式為 `HH:MM NAME已收回訊息`。

若 LINE 匯出格式為 `HH:MM NAME 已收回訊息`(名稱後有空白),`_RECALL_RE` 無法匹配,此行會進入 `_MSG_RE` 匹配,將「已收回訊息」視為普通訊息內容,失去語意標記。

建議修正為:

```suggestion
_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?) 已收回訊息$')
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai 匯出的檔案姓名和已收回訊息之間沒有空格

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

問題出在 _RECALL_RE 正則表達式中,姓名捕獲組 (\S+?) 和「已收回訊息」之間缺少空格。

對照一般訊息的格式 _MSG_RE:

_MSG_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?) (.+)$')

收回訊息也應該在姓名後有空格:

_RECALL_RE = re.compile(r'^(\d{2}:\d{2}) (\S+?) 已收回訊息$')

@keyang556
Copy link
Copy Markdown
Owner Author

@greptileai@greptileai 現在要怎麼修正

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

刪除 _messageReaderHandleSaveDialog 函式開頭的那行 import tempfile 即可(就是緊接在 import ctypes.wintypes as wintypes 後面的那行)。保留後面註解「Build temp file path...」附近的 import tempfile 就好。

@keyang556 keyang556 merged commit d38544c into main Apr 9, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant