サポンテ 勉強ノート

サポンテの勉強ノート・読書メモなどを晒します。

最近ブラウザで開いた Web ページの Markdown リンクを CotEditor に挿入する【Safari/Chrome/CotEditor/Markdown/AppleScript/Swift】

はじめに

 サポンテは CotEditor を用いて Markdown ドキュメントを書いていますが、Markdown のリンクを作るのにブックマークレットを使っていました。

 ですが、いちいちアプリケーションを切り替えるのと、クリップボードを経由するのがなんとなく煩わしく感じてきました。

 AppleScript を用いれば、Safari で開いているページから Markdown リンクを作成して編集中の CotEditor 書類に挿入できるはずです。

 誰かが既に作っていそうですが「AppleScript Safari CotEditor Markdown link」などのキーワードで軽く検索した限りでは、CotEditor 用のスクリプトは見つかりませんでした。

 しかし「アプリケーションからリンクを取得する」という点に限って言えば AppleScript はたくさんありました。

 これなんかすごいですね。スゴすぎる。:Get Front Mac App Title and URL and make a Markdown Link to it

SafariGoogle Chrome だけでいいかな

 今のところ Safari だけで用は足りるのですけれども、そのうち Google Chrome も併用することになるかもしれないで、上記のスクリプトから切り出して作ってみますね。

 ただ CotEditor スクリプトで動かすということは frontmost application は CotEditor なので「二番目以降のアプリケーション」を「順番に」取得しないといけない(笑)。

完成したスクリプト

 意外と梃子摺った...。Swift も併用しました。ここまでやる必要があったでしょうか。

 下記 Swift プログラムを .appList.swift として、その次の AppleScript と一緒に CotEditor のスクリプトフォルダに入れてください。

Swift による補助スクリプト

 起動中のドキュメントウィンドウを開いているアプリケーション一覧を上から順に取得する Swift スクリプトです。

 AppleScript から呼び出すので、次のようにしてください。

  • AppleScript の本体スクリプトと同じフォルダに配置してください。
  • このスクリプト自体はメニュに表示したくないので、ファイル名は .appList.swift としてください。
  • ターミナルで、実行権を付与してください。chmod a+x .appList.swift
  • ターミナルで、./.appList.swift としてアプリケーションの一覧が表示されれば OK です。
#!/usr/bin/swift

// Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
// Target: x86_64-apple-darwin19.6.0

import Foundation
import Cocoa

// 起動中のウィンドウのプロセス一覧を取得する
let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
let windowList = CGWindowListCopyWindowInfo(options, CGWindowID(0))
let windows = windowList as NSArray? as! [[String: AnyObject]]

var ids = [pid_t]()

for window in windows {
    let pid = pid_t(window[kCGWindowOwnerPID as String]! as! Int)
    ids.append(pid)
}

// 重複行を出さないための配列を初期化する
var apps = [NSRunningApplication]()

// プロセス ID からアプリケーション名に変換して出力していく
for id in ids {
    // 変換
    let app = NSWorkspace.shared.runningApplications.filter { (app) -> Bool in
        app.activationPolicy == .regular && id == app.processIdentifier
    }.first
    
    // 変換結果の確認
    if app == nil {
        continue
    }
    
    // 既に出力済みかどうか確認する
    if apps.contains(app!) {
        continue
    }
    
    // アプリケーション名を出力する
    print(app?.bundleIdentifier ?? "")
    
    // 出力済みアプリケーションを記録しておく
    apps.append(app!)
}

AppleScript による CotEditor スクリプト

 本体スクリプトです。スクリプトエディタにコピペして、スクリプトとして CotEditor のスクリプトフォルダに保存してください。ファイル名はなんでも良いです。CotEditor のスクリプトメニューのメニュー名になります。

-- 開発環境:
-- AppleScript 2.7
-- CotEditor 4.0.2(457)
-- macOS Catalina 10.15.7

set theApplication to ""
set theText to ""
set theBody to ""

-- コマンドを実行して、ドキュメントウィンドウを開いているアプリケーションのリストを取得する
set current_path to ""
tell application "Finder"
    set current_path to (POSIX path of (container of (path to me) as alias))
end tell

log current_path

set r_path to current_path & ".appList.swift"
set appListSrc to do shell script "/usr/bin/swift " & "'" & r_path & "'"
set appList to paragraphs of appListSrc

log appList

-- 最近操作したブラウザウィンドウから、URL とタイトルを取得する
repeat with theApplication in appList
    log (theApplication as string = "com.google.Chrome")
    if theApplication as string = "com.google.Chrome" then
        tell application id "com.google.Chrome"
            using terms from application "Google Chrome"
                set theText to title of active tab of first window
                set theBody to get URL of active tab of first window
            end using terms from
        end tell
        exit repeat
    else if theApplication as string = "com.apple.Safari" then
        tell application id "com.apple.Safari"
            using terms from application "Safari"
                set theTab to front document
                set theText to name of theTab
                set theBody to URL of theTab
            end using terms from
        end tell
        exit repeat
    end if
end repeat

if theBody = "" then
    display notification "CotEditor の次に有効なアプリケーションが対応ブラウザではないようです。" with title "ブラウザ不明"
end if

-- CotEditor に Markdown を挿入する
tell application "CotEditor"
    if not (exists front document) then
        make new document
    end if
    
    set selectedText to contents of selection of front document
    if selectedText /= "" then
        set theText to selectedText
    end if
    
    tell front document
        set contents of selection to ("[" & theText & "](" & theBody & ")")
    end tell
end tell

使い方

 スクリプトを起動すると、開いているブラウザ画面でもっとも近いものからタイトルと URL を取得して CotEditor に挿入します。

 CotEditor で選択中の文字列があると、それをタイトルとして使用します。

参考