context menu ext
最終更新日時: 2025年08月25日 12:57
- レジストリを扱うため一旦開発停止詳細確認後に再開想定
Chrome拡張機能「Open with Emacs」内部技術仕様
Section titled “Chrome拡張機能「Open with Emacs」内部技術仕様”この拡張機能は、Chrome上でAstro/Starlightで生成されたWebサイト(localhost:4321)を閲覧中に、リンクを右クリックして「Open with Emacs」を選択することで、対応するソースファイル(.mdx)をWSL2上のEmacsで開くためのものです。
構成ファイル
Section titled “構成ファイル”- manifest.json - 拡張機能の基本情報
- background.js - バックグラウンドスクリプト(コンテキストメニュー処理)
- com.emacs.open.json - Native Messaging Host マニフェスト
- emacs-edit-extionsion.bat - WSLのEmacsを起動するバッチファイル
- register_host.bat - Native Messaging Hostをレジストリに登録
- unregister_host.bat - Native Messaging Hostをレジストリから削除
manifest.json
Section titled “manifest.json”- Manifest V3形式
- 必要なパーミッション: contextMenus, tabs, nativeMessaging
- ホストパーミッション: http://localhost/, https://localhost/
- バックグラウンドスクリプトをサービスワーカーとして定義
background.js
Section titled “background.js”- 拡張機能インストール時にコンテキストメニュー「Open with Emacs」を作成
- メニュー表示条件: localhost:4321上のリンクのみ
- リンクURLからファイルパス変換ロジック:
- 末尾のスラッシュを削除
- .mdx拡張子を追加(ない場合)
- 先頭のスラッシュを削除
- Native Messagingを使用してホストにメッセージ送信
chrome.runtime.connectNative("com.emacs.open").postMessage({path: filePath})
com.emacs.open.json
Section titled “com.emacs.open.json”- Native Messaging Host定義ファイル
- ホスト名: com.emacs.open
- 実行ファイル: C:\Users\aquis\bin\emacs-edit-extionsion.bat
- 通信方式: stdio
- 許可されたオリジン: 拡張機能ID emkdafpgmnepaifibdfgoinchgkgaflb のみ
emacs-edit-extionsion.bat
Section titled “emacs-edit-extionsion.bat”- 標準入力からJSONを読み取り
- パスプロパティを抽出(シンプルなJSON解析)
- WSL向けにパスを変換(/mnt/c/Users/akihisa/astro/src/contents/docs/をプレフィックスとして使用)
- emacsclientを使用してファイルを開く
register_host.bat
Section titled “register_host.bat”- マニフェストディレクトリ作成: %USERPROFILE%\AppData\Local\Google\Chrome\User Data\NativeMessagingHosts
- マニフェストファイル生成: com.emacs.open.json
- レジストリ登録: HKCU\Software\Google\Chrome\NativeMessagingHosts\com.emacs.open
unregister_host.bat
Section titled “unregister_host.bat”- レジストリキー削除: HKCU\Software\Google\Chrome\NativeMessagingHosts\com.emacs.open
- マニフェストファイル削除
内部処理フロー
Section titled “内部処理フロー”- ユーザーがリンクを右クリックしてコンテキストメニュー「Open with Emacs」を選択
- バックグラウンドスクリプトがリンクURLを処理
- 例: http://localhost:4321/tech/migration/ → tech/migration.mdx
- Native Messaging Hostにパス情報を送信
- バッチファイルがJSONを受け取り、パスを抽出
- WSL用のパスに変換して、emacsclientコマンドを実行
- 例: /mnt/c/Users/akihisa/astro/src/contents/docs/tech/migration.mdx
- Native Messaging Hostの登録には一度だけレジストリ操作が必要
- 拡張機能IDは同じディレクトリから読み込む限り変更されない
- Windows/WSLのパス変換は固定パスを前提としている
manifest.json
Section titled “manifest.json”{ "manifest_version": 3, "name": "Open with Emacs", "version": "1.0", "description": "Right-click on a link to open it with Emacs", "permissions": ["contextMenus", "tabs", "nativeMessaging"], "host_permissions": ["http://localhost/*","https://localhost/*"], "background": { "service_worker": "background.js" }}background.js
Section titled “background.js”chrome.runtime.onInstalled.addListener(() => { console.log("Extension installed - creating context menu"); chrome.contextMenus.create({ id: "openWithEmacs", title: "Open with Emacs", contexts: ["link"], documentUrlPatterns: ["http://localhost:4321/*"] }); console.log("Context menu created");});
chrome.contextMenus.onClicked.addListener((info, tab) => { console.log("Context menu clicked:", info.menuItemId);
if (info.menuItemId === "openWithEmacs") { console.log("Original link URL:", info.linkUrl);
const url = new URL(info.linkUrl);
// URLからファイルパスを変換する処理 let filePath = url.pathname; console.log("Initial filePath:", filePath);
// 末尾のスラッシュを削除 if (filePath.endsWith('/')) { filePath = filePath.slice(0, -1); console.log("After removing trailing slash:", filePath); }
// /tech/migration/ → tech/migration.mdx のような変換 if (!filePath.endsWith('.mdx')) { filePath = filePath + '.mdx'; console.log("After adding .mdx extension:", filePath); }
// 先頭のスラッシュを削除 if (filePath.startsWith('/')) { filePath = filePath.slice(1); console.log("After removing leading slash:", filePath); }
const messageData = { path: filePath }; console.log("Sending message to native host:", messageData);
try { // Chrome Manifest V3での正しいNative Messaging呼び出し chrome.runtime.connectNative("com.emacs.open").postMessage(messageData); console.log("Native message sent via connectNative"); } catch (error) { console.error("Exception when sending native message:", error); } }});
console.log("Background script loaded");com.emacs.open.json
Section titled “com.emacs.open.json”{ "name": "com.emacs.open", "description": "Open .mdx files with Emacs", "path": "C:\\Users\\aquis\\bin\\emacs-edit-extionsion.bat", "type": "stdio", "allowed_origins": [ "chrome-extension://emkdafpgmnepaifibdfgoinchgkgaflb/" ]}emacs-edit-extionsion.bat
Section titled “emacs-edit-extionsion.bat”@echo offset /p json=echo Received JSON: %json% >> "%USERPROFILE%\emacs_debug.log"
for /f "tokens=2 delims=:}" %%a in ("%json%") do ( set rawpath=%%a)
set rawpath=%rawpath:"=%set rawpath=%rawpath: =%set filepath=%rawpath%
echo Final filepath: %filepath% >> "%USERPROFILE%\emacs_debug.log"
wsl emacsclient -n "/mnt/c/Users/akihisa/astro/src/contents/docs/%filepath%"echo Command result: %ERRORLEVEL% >> "%USERPROFILE%\emacs_debug.log"register_host.bat
Section titled “register_host.bat”@echo offecho === Native Messaging Host Registration Script ===
SET REGISTRY_KEY=HKCU\Software\Google\Chrome\NativeMessagingHosts\com.emacs.openSET HOST_MANIFEST_DIR=%USERPROFILE%\AppData\Local\Google\Chrome\User Data\NativeMessagingHostsSET HOST_MANIFEST_FILE=%HOST_MANIFEST_DIR%\com.emacs.open.json
SET EXTENSION_ID=emkdafpgmnepaifibdfgoinchgkgaflb
if not exist "%HOST_MANIFEST_DIR%" ( echo Creating directory: %HOST_MANIFEST_DIR% mkdir "%HOST_MANIFEST_DIR%" echo Directory created successfully.) else ( echo Directory already exists: %HOST_MANIFEST_DIR%)
echo Creating manifest file: %HOST_MANIFEST_FILE%echo {^ "name": "com.emacs.open",^ "description": "Open .mdx files with Emacs",^ "path": "C:\\Users\\aquis\\bin\\emacs-edit-extionsion.bat",^ "type": "stdio",^ "allowed_origins": [^ "chrome-extension://%EXTENSION_ID%/"^ ]^} > "%HOST_MANIFEST_FILE%"echo Manifest file created successfully.
echo Registering in Windows registry: %REGISTRY_KEY%REG ADD "%REGISTRY_KEY%" /ve /t REG_SZ /d "%HOST_MANIFEST_FILE%" /fIF %ERRORLEVEL% EQU 0 ( echo Registry key created successfully.) ELSE ( echo Failed to create registry key. Error code: %ERRORLEVEL%)
echo === Registration Summary ===echo Registry Key: %REGISTRY_KEY%echo Manifest File: %HOST_MANIFEST_FILE%echo Extension ID: %EXTENSION_ID%echo Status: Registration complete
pauseunregister_host.bat
Section titled “unregister_host.bat”@echo offecho === Native Messaging Host Unregistration Script ===
SET REGISTRY_KEY=HKCU\Software\Google\Chrome\NativeMessagingHosts\com.emacs.openSET HOST_MANIFEST_DIR=%USERPROFILE%\AppData\Local\Google\Chrome\User Data\NativeMessagingHostsSET HOST_MANIFEST_FILE=%HOST_MANIFEST_DIR%\com.emacs.open.json
echo Checking registry key: %REGISTRY_KEY%REG QUERY "%REGISTRY_KEY%" /ve >nul 2>&1IF %ERRORLEVEL% EQU 0 ( echo Registry key exists. Deleting... REG DELETE "%REGISTRY_KEY%" /f IF %ERRORLEVEL% EQU 0 ( echo Registry key deleted successfully. ) ELSE ( echo Failed to delete registry key. Error code: %ERRORLEVEL% )) ELSE ( echo Registry key does not exist or cannot be accessed.)
echo Checking manifest file: %HOST_MANIFEST_FILE%IF EXIST "%HOST_MANIFEST_FILE%" ( echo Manifest file exists. Deleting... DEL /F "%HOST_MANIFEST_FILE%" IF %ERRORLEVEL% EQU 0 ( echo Manifest file deleted successfully. ) ELSE ( echo Failed to delete manifest file. Error code: %ERRORLEVEL% )) ELSE ( echo Manifest file does not exist.)
echo === Unregistration Summary ===echo Registry Key: %REGISTRY_KEY%echo Manifest File: %HOST_MANIFEST_FILE%echo Status: Unregistration complete
pause内部処理フロー
Section titled “内部処理フロー”- ユーザーがリンクを右クリックしてコンテキストメニュー「Open with Emacs」を選択
- バックグラウンドスクリプトがリンクURLを処理
- 例:
http://localhost:4321/tech/migration/→tech/migration.mdx
- 例:
- Native Messaging Hostにパス情報を送信
- バッチファイルがJSONを受け取り、パスを抽出
- WSL用のパスに変換して、emacsclientコマンドを実行
- 例:
/mnt/c/Users/akihisa/astro/src/contents/docs/tech/migration.mdx
- 例:
- Native Messaging Hostの登録には一度だけレジストリ操作が必要
- 拡張機能IDは同じディレクトリから読み込む限り変更されない
- Windows/WSLのパス変換は固定パスを前提としている
- デバッグログは
%USERPROFILE%\emacs_debug.logに出力される