Archive for the 'TextEdit' Category

2015/01/07 【基礎】アプリケーションの操作は、用語辞書に書いてあるとおり記述しないと動かない

「コンピュータは、あなたが思ったとおりには動かないが、操作したとおりに動く」

名言だと思います。同様に、

「プログラムは、あなたが思った/願ったようには動かないが、書いたとおりに動く」

と言い換えることが可能です。さらに、

「AppleScriptは、あなたが願ったようには動かないが、書いたとおりに動く」

とも言い換えられます。とくに、アプリケーションの操作については「AppleScript用語辞書」に書いてあるとおりに書くのが鉄則です。それ以外の書き方をして「動いてしまった」としても、その方が不思議なわけで。

自分でも、海外のScripter連中でもそうだと思うのですが、Scriptを書いている最中は、AppleScript用語辞書を数枚ひらきっぱなしです。AppleScriptObjCのプログラムを書いているときには、AppleのReferenceサイトも表示させっぱなしです。さらに難問になってくるとUS AppleのAppleScript Users MLとか、www.macscripter.netとかを検索しまくることになり複数モニタが欠かせません(3枚使っているといったらShane Stanleyに「ずいぶん枚数多いな!」と驚かれましたが、、、)。

ひと昔前(Classic Mac OSの時代)、AppleScript用語辞書はわざわざ人間(開発者)が書くもので、さらに実際のアプリケーション側の機能とリンクしていない「ただの書き方見本」だったので、「用語辞書には書いていないけれど使える」とかいう「隠し命令」なんてものもありました(初代のEntourageとか)。単なる書きもれ、ケアレスミスでしたが、マニアさんの間では「隠し命令」の存在がちょっと「通」な話題になっていたりしました。

いまのAppleScript用語辞書はXMLファイル(sdefファイル)で、この用語辞書がイコールAppleEventの解釈用の辞書であって、「書き方見本」ではありません。そのため「隠し命令」が存在する余地というのはありません。逆にいえば、用語辞書のとおりに動かなかったら完全なバグなわけです(実装が「不完全」「残念」なために期待したとおりに動かないというKeynote/Numbers/Pagesは例外として)。

たまたま、魔が差してTwitter上で議論になったのですが・・・アプリケーションにファイルをオープンさせる場合には、AppleScript用語辞書をScript Editorでオープンして、コマンドなりオブジェクトなりの使い方を調べることになります。このあたり、Objective-CでCocoaのAPIの使い方をAppleのサイトで調べながら書くのと同じです。AppleScript用語辞書は、アプリケーションバンドル内にあってScript Editorからオープンできます。

textedit_asdic.png

で、この「AppleScript用語辞書を見る」ことをしない方がけっこう多いようで・・・逆にこれを見ないでよくプログラムが書けるもんだと感心してしまうんですが、用語辞書を見ないとハマりやすいんですね。

前述のように、アプリケーションの操作は「決められたとおりに書かないと正しく動かない」ものであり、さらにその先に「ファイルをオープンもしないで中を調べたりはできないよ」といったアプリケーションの挙動(経験則に基づく)の話になるわけなんですけれども、まずは用語辞書を見ないと分かりません。

アプリケーションで書類をオープンする際には、ごく一部の残念な例外(Adobeのアプリ)をのぞいては、パス情報をaliasにしてopenコマンドに渡す必要があります。

textedit_open.png

ここで、POSIX pathやらfileやらを渡してもオープンはしないわけです。

AppleScript用語辞書には「openコマンドにはaliasを渡してね」と書いてあるので、

textedit_open.png

alias以外を渡すのはアウトです(aliasのlistはOK)。それ以外の形式のパス情報を渡して、たまたま間違って動いていたとしても、たまたまです。それ以上でも、それ以下でもありません。

最近は、AppleScript用語辞書にHTMLコンテンツを入れることができるようになり、一部のアプリケーションでは用語辞書内にサンプルScriptを掲載しだして、「サンプルをそのままコピペで動く」いい時代になってきたはずなんですが、これまた残念なことに「Apple社内の連中が書くScriptが絶望的に読みにくい」ために(theとかresultとか使いまくる&1行を長く記述して初心者にわかりにくい)、サンプルを読むと逆に理解しづらくなるという事態が(ーー;;

もういっそのこと、アプリケーションバンドル内に、典型的な利用法を記述したAppleScript Librariesを内蔵してしまって、Scriptから呼び出せるようにすべきではないかとも考える次第です。

余談:

途中から(OS X 10.8あたり?)挙動が変わってしまって困っていた、Mail.appのmove命令。前は複数のmessageをlistに入れて一気にmoveできていたのが、1つのmessageしかmoveできないように変わり、処理速度を稼げなくなっていました(複数一度にmoveできたほうが速い)。

いましらべたら、

mailapp_move.png

複数のmessageを示すobject(s)の表記がありますね。でも、「Move an object to new location」とも書いてあり・・・微妙な。

2010/11/26 テキストエディットの文章のうち赤くマークされた行をカウントする

テキストエディットの文章のうち、赤く(R=65535)マークされた行をカウントするAppleScriptです。

ted01.jpg

AppleScriptObjC(ASOC)のサンプルプログラムを作成し、そのうちASOC由来のコードと通常のAppleScriptのコードを個別にカウントするため、ASOCのコードに赤く色を塗っておいてカウントさせてみました。

スクリプト名:TextEditの文章のうち赤くマークされた行をカウントする

set rNum to 0

tell application “TextEdit”
  tell text of document 1
    set pCount to (count paragraphs)
    
    
repeat with i from 1 to pCount
      set aCol to color of paragraph i
      
if aCol = {65535, 0, 0} then –{r, g, b}
        set rNum to rNum + 1
      end if
    end repeat
    
  end tell
end tell

return {pCount, rNum}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/12/19 TEXT/RTF/HTMLから本文を取り出す

指定したTEXTファイル、RTF、HTMLから本文を取り出すAppleScriptです。

AppleScript Users MLに流れていたScriptで、これはなかなかいいアイデアだと思います。とくに、RTFから本文部分を取り出すのは面倒だと考えていたので、テキストエディットにopenさせて内容を取り出させるというのは盲点でした。

こんな、いろいろ書式情報が付加されたRTF(Ritch Text Format)ファイルから内容を取り出せます。
rtfscreen.jpeg

これだけ手軽に取り出せるのはいいですね。ただ、肝心のTEXTファイルについては……テキストエディットでそのまま(文字エンコーディングを指定しないで)オープンできるケースとできないケースがあるため、実は何も考えないでオープンできるのはRTF/RTFDぐらいではないかと思えなくもありません。

処理前にファイルタイプを調べ、RTF/RTFDであれば本ルーチンで内容を取り出す、ぐらい慎重に処理すべきでしょう。

スクリプト名:テキスト、RTF、HTMLから内容を取り出す
set theFile to choose file with prompt “Select a text file:”
set aRes to getContentsFromTXT_PDF_HTML(theFile) of me
–>
(*
“RTF
のファイルだよーん。

*)

–選択したテキスト、RTF、HTMLから内容を取り出す
on getContentsFromTXT_PDF_HTML(theFile)
  tell application “TextEdit”
    set myDoc to open theFile
    
set theFileContents to the text of myDoc
    
close myDoc
  end tell
  
return theFileContents
end getContentsFromTXT_PDF_HTML

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/05/05 テキストエディットでリッチテキストのファイルをプレーンテキストに

テキストエディットでオープンしているリッチテキスト書類をプレーンテキストに変換するAppleScriptです。

texte1.jpg

save as textで保存形式を指定して別名で保存すると、プレーンテキストに変換されます。

スクリプト名:テキストエディットでリッチテキストのファイルをプレーンテキストに
set anAlias to choose file name
tell application "TextEdit"
  tell document 1
    save as text in anAlias
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/04/29 テキストエディットで文字数をカウントする

テキストエディットの最前面の文章内の文字数をカウントして知らせるAppleScriptです。

ted1.jpg

スクリプトメニューにでも入れておいて呼び出すと便利でしょう。テキストエディットはOS標準装備のテキストエディタとしては異様に高機能であり、文字コードがどーのこーのと騒がないかぎりはたいていの用事が済んでしまうほどです。

ただ、自己紹介文を200〜240文字で……などと言われたときに、そういう気の利いた機能はありません。

テキストエディット上の文章をスクリプトエディタに貼り込んでlengthを求めるようなことは……自分はよくやりますが、それを身の回りのMacユーザーに強制するのもかわいそうなので、その場でささっと作ってみました。

スクリプト名:TextEditで文字数をカウントする
tell application TextEdit
  tell text of document 1
    set textList to characters of every attribute run
  end tell
  
  
set textAll to textList as string
  
set tLen to length of textAll
  
display dialog (tLen as string) & 文字です with title この文章の文字数は… buttons {”OK“} default button 1 with icon 1
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/02/11 Keynote上でコピーされたテキストオブジェクトの内容をTextEditで解析してIllustratorで白フチ文字を作成してKeynoteにペースト

iWork ‘09のKeynote 5.x上で文字オブジェクトをコピーし、実行すると白フチ文字に変換してKeynote上にペーストする(趣味の)AppleScriptです。

まずは、Keynote上で文字オブジェクトをコピーして本Scriptを実行。

keynote1.jpg

クリップボードに入っているデータ(Ritch Text Format)をテキストエディットの新規書類にペースト。テキストエディット上で書式などを分析します。分析したら、用済みのテキストエディット書類は破棄。

テキストエディット上で得られた情報をもとに、今度はIllustrator CS3上で同様にオブジェクトを組み立て、白フチ文字を作成。白フチ文字のオブジェクトをコピーして、Illustrator書類を破棄します。

最後に、Keynoteを最前面に持ってきてSystem Eventsで(GUI Scriptingで)ペースト操作を実行。

keynote2.jpg

keynote3.jpg

以前に作成しておいたルーチンに一部手を加えて、縦方向の文字(1文字ごとに改行)でも、横方向の文字(通常)でも対応します。ただし、本バージョンではオリジナルのフォント情報までは白フチ文字に反映していません。

keynote4.jpg

スクリプト名:Keynote上でコピーされたテキストオブジェクトの内容をTextEditで解析してIllustratorで白フチ文字を作成してKeynoteにペースト

何もコピーされていなければリターン
set a to the clipboard
if a = “” then return

Text Editで新規ドキュメントを作成してコピーされていたデータをコピー
tell application TextEdit
  set aDoc to make new document
  
activate
end tell

tell application System Events
  tell process TextEdit
    keystroke v using {command down}
  end tell
end tell

TextEditの書類上から各種情報を取得する
tell application TextEdit
  tell text of aDoc
    set colorList to color of every attribute run
    
set fontList to font of every attribute run
    
set sizeList to size of every attribute run
    
set textList to characters of every attribute run
    
    
set itemCount to length of colorList
    
    
set contList to {}
    
repeat with i from 1 to itemCount
      set aRec to {textData:(item i of textList) as string, colorData:item i of colorList, fontData:item i of fontList, sizeData:item i of sizeList}
      
set the end of contList to aRec
    end repeat
  end tell
end tell

tell application TextEdit
  tell document 1
    close without saving
  end tell
end tell

set aDirection to detectTextDirection(textList) of me
> “vertical” / “horizontal”

set aFontName to contents of item 1 of fontList
set aSize to contents of item 1 of sizeList
set aLineWidth to aSize / 8
set aLineWidth to round aLineWidth rounding up

set aCon to textList as string
set aCon to repChar(aCon, ASCII character 10, “”) of me
set aColor to item 1 of colorList
set rColor to (item 1 of aColor) / 256
set rColor to round rColor rounding down
set gColor to (item 2 of aColor) / 256
set gColor to round gColor rounding down
set bColor to (item 3 of aColor) / 256
set bColor to round bColor rounding down
set colorList to {rColor, gColor, bColor}

makeTextGraphicWithEdgeLine(aCon, aSize, aLineWidth, aDirection, aFontName, colorList) of me

tell application Keynote
  activate
end tell

tell application System Events
  tell process Keynote
    keystroke v using {command down}
  end tell
end tell

以下、サブルーチン

Attribute runsのテキストデータの並びから、Keynote上で縦書き/横書きだったかの判定を行う
on detectTextDirection(aList)
  set normCount to 0
  
set retCount to 0
  
log aList
  
repeat with i in aList
    set jj to contents of (item 1 of i)
    
set j to id of (contents of jj)
    
display dialog (string id of j)
    
if (j = 10) or (j = 13) then
      set retCount to retCount + 1
    else
      set normCount to normCount + 1
    end if
  end repeat
  
  
set vhCalc to (retCount / normCount)
  
  
if vhCalc > 0.5 then
    return vertical
  else
    return horizontal
  end if
  
end detectTextDirection

on makeTextGraphicWithEdgeLine(aCon, aSize, aLineWidth, aDirection, aFontName, colorList)
  copy colorList to {rColor, gColor, bColor}
  
  
using terms from application Adobe Illustrator
    tell application Adobe Illustrator
      set aDoc to make new document with properties {color space:RGB}
      
      
tell aDoc
        setOriginToLeftCorner() of me
        
        
set aGroup to make new group item
        
        
set aFrame1 to make new text frame at the end of aGroup
        
tell aFrame1
          set position to {0, 0}
          
set contents to aCon
          
if aDirection = vertical then
            set text orientation to vertical
          else if aDirection = horizontal then
            set text orientation to horizontal
          end if
          
tell every character
            set size to aSize
            
set font to aFontName
            
set stroke weight to aLineWidth ふちどり線の太さ
            
set stroke color to {red:255, green:255, blue:255}
          end tell
        end tell
        
        
set aFrame2 to make new text frame at the beginning of aGroup
        
tell aFrame2
          set contents to aCon
          
set position to {0, 0}
          
if aDirection = vertical then
            set text orientation to vertical
          else if aDirection = horizontal then
            set text orientation to horizontal
          end if
          
tell every character
            set size to aSize
            
set font to aFontName
            
set stroke weight to 0.0
            
set fill color to {red:rColor, green:gColor, blue:bColor}
          end tell
        end tell
        
        
        
set selection to aGroup
        
copy ふちどり文字をクリップボードにコピー
        
        
close saving no Illustratorの書類を破棄する
      end tell
    end tell
  end using terms from
end makeTextGraphicWithEdgeLine

Illustratorの原点座標を変更する
on setOriginToLeftCorner()
  using terms from application Adobe Illustrator
    tell application Adobe Illustrator
      tell document 1
        set aHeight to height
        
set ruler origin to {0, aHeight}
      end tell
    end tell
  end using terms from
end setOriginToLeftCorner

Written By Philip Aker
文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2008/12/30 テキストエディットで選択中のテキストを取得する

テキストエディットはOS標準搭載のエディタにしてはよく出来たエディタですが、いくつかの基本的な機能が欠落しています。それが、ドキュメント上の選択内容(selection)を取得する機能であり、Scriptableなアプリケーションが当然のように備えていることを期待されるものです。
(more…)

2008/04/11 TextEditでドキュメントから全属性を取得する

Apple純正なのにやたらとAppleScriptから操作しづらく、「悪しき実装例」「AppleのAppleScript対応が一番へたくそ」「サードパーティにScript対応を薦めているのに自分たちの体たらくはなんなんだ?」と名指しで全世界のScripterに非難されているTextEditを操作して、ドキュメントから全属性を取得するサンプルです。本来、カラー、フォント、サイズ、テキストは別々に取得されていますが、扱いやすいようにまとめています。

textedit2.jpg

スクリプト名:TextEditでドキュメントから全属性を取得する
tell applicationTextEdit
  tell text of document 1
    set colorList to color of every attribute run
    
set fontList to font of every attribute run
    
set sizeList to size of every attribute run
    
set textList to characters of every attribute run
    
    
set itemCount to length of colorList
    
    
set contList to {}
    
repeat with i from 1 to itemCount
      set aRec to {textData:(item i of textList) as string, colorData:item i of colorList, fontData:item i of fontList, sizeData:item i of sizeList}
      
set the end of contList to aRec
    end repeat
  end tell
end tell

contList

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2008/04/11 TextEditでWordごとにColorを取得

TextEditで、本文をWord単位で文字色を調べます。Word単位といっても日本語に対しては文字種類の変わり目を便宜上Wordと呼んでいるだけです。Microsoft Word v.Xのように形態素解析して本当に文法的なWordを返してくれたりすることはありません。

textedit1.jpg

スクリプト名:TextEditでWordごとにColorを取得
tell applicationTextEdit
  tell text of document 1
    repeat with i from 1 to (count words)
      set aCol to color of word i
      
log aCol
    end repeat
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に