Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

タグ: Script Editor

AppleScript書類冒頭のコメントを書き換える

Posted on 10月 6 by Takaaki Naganoya

指定フォルダ以下のすべてのAppleScript書類(通常書類、バンドル書類)をSpotlightで検出して、各書類の冒頭に書いてあるヘッダーコメントをすべて書き換えて保存するAppleScriptです。

–> Download scriptHeaderReplacer.zip (Code-Signed executable AppleScript applet with Libraries in its bundle)

AppleScriptの自動組み立て&自動書き出しといった処理は、macOS 10.4ぐらいの時期、あるいはScript DebuggerをコントロールしてClassic MacOSの時代からやっていた記憶があります。AppleScriptをAppleScriptで書くとか書き換えるといった処理は、割と重箱の隅をつつくような(メーカー側も想定していないわけではないだろうけれど、そんなに検証してなさそう)ものなので、未知の問題に遭遇することの多いものです。ただし、安定して動作させられれば得るものも大きいです。

CotEditorの配布用サンプルScriptをまとめる際に、ヘッダーコメント部分を統一する作業がなにげに大変でした。そこで、本Scriptを作成して一括してAppleScript書類のヘッダーコメント統一を行えるようにしました。60ファイル程度あるので、すべて手作業で書き換えるのは非効率的です(サンプルを書くよりも本Scriptを書くほうが時間がかかりました。でも、一度書けば2度目以降は自動で処理できます)。

本AppleScriptでは、Script EditorをコントロールしてAppleScript書類の書き換えを行っています。ただし、AppleScript書類自体の詳細な書式情報はCocoaの機能を用いて抽出しています。Script Editorで書き換えを行っているのは「目で見て動作を確認できる」からで、それ以外にはScript Editorをコントロールするメリットはありません(Cocoa側の機能を用いてScriptの修正と保存ができれば、すぐにでも本ワークフローから外したい)。

AppleScriptの構文色分け書式にアクセスして構文要素を文字色で区分けしているため、本Scriptの実行環境で構文色分け書式がデフォルトのままとか、各構文要素の指定色でごくごく似たものがあったような場合には正常に動作しません。

Script名称が「AppleScript書類冒頭のコメントを削除する v4」になっているのは、コメントを追加するプログラムとコメントを削除するプログラムの2系統のものを別々に作って、最終的に「コメントを削除するプログラム」に機能を統合したためです。

メインのScriptの内容のみ掲載していますが、(巨大な)ライブラリ入りのScript掲載は頭が痛いところです。とりあえず、実行して試せるということを重視してみました。

AppleScript名:AppleScript書類冒頭のコメントを削除する v4.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/10/03
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use asAttr : script "asAttrRecLib" –AppleScript書類をattribute runs的に書式データ化するライブラリ
use asCom : script "asCommentLib" –AppleScript書類から構文色分け情報にもとづいてコメントを抽出するライブラリ
use dsipTV : script "displayTextView" –NSTextViewで比較的長いテキスト入力(元テキストの修正程度を行うライブラリ
use script "Metadata Lib" version "2.0.0" –https://macosxautomation.com/applescript/apps/Script_Libs.html

–新しいヘッダーコメント(ダイアログ上でさらに変更可能)
set hRes to "–
–  Created by: Takaaki Naganoya
–  Created on: 2019/10/06
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
–  http://www.piyocast.com

"

–ヘッダーの入力・修正を促す
set aHeader to (input text view hRes main message "Input New Header" sub message "Input AppleScript header text to replace" with properties {font name:"HiraMinProN-W6", size:20.0, width:800, height:200})

–AppleScriptの構文色分け設定から、コメントのカラーを取得する(色書式検索用 R、G、B値が1つの文字列にまとまっている形式)
set comColStr to (getCommentColStr() of asCom) as string

–指定フォルダ以下のAppleScript書類をSpotlight検索ですべてリストアップ
set aFol to choose folder with prompt "Select Root Folder"
set resList to perform search in folders {aFol} predicate string "kMDItemContentType IN %@" search arguments {"com.apple.applescript.script", "com.apple.applescript.script-bundle"}

–各AppleScript書類でループ
repeat with i in resList
  
  
–ファイルをScript Editorでオープン
  
set j to POSIX file (contents of i)
  
tell application "Script Editor"
    try
      open j
    on error
      display dialog "Error in opening"
      
return
    end try
    
    
    
–ヘッダーコメントの書き換え処理
    
tell front document
      set aCon to contents
      
      
if aCon does not start with "–" then
        –ヘッダーコメントが存在しなかった場合
        
set aCon to aHeader & aCon
        
set contents to aCon
        
      else
        –ヘッダーコメントが存在した場合
        
–既存のヘッダーを外してヘッダーコメントを付加
        
        
–AppleScript書類の冒頭のヘッダーコメントの範囲を書式情報から取得する
        
set tmpLoc to retHeaderCommentRange(comColStr, j as alias, aHeader) of me
        
delay 0.5 —ないとうまく動作しない
        
        
–既存のヘッダーコメントのテキストを取得する
        
set aText to (text 1 thru tmpLoc of aCon)
        
        
–ヘッダーコメントの削除
        
set pStr to repChar(aCon, aText, "") of me
        
        
set contents to aHeader & pStr
      end if
      
      
check syntax
      
delay 0.5 —ないとうまく動作しない
      
    end tell
    
    
close every document with saving
    
delay 0.5 —ないとうまく動作しない
    
  end tell
end repeat

–上記のclose命令をすり抜ける書類があるので、最後にまとめてクローズ
tell application "Script Editor"
  close every document with saving
end tell

–パスで与えられたAppleScript書類の冒頭からのヘッダーコメントの範囲を求める
on retHeaderCommentRange(comColStr as string, aFile, aHeader as string)
  set aList to (getAttrRecFromASPath(aFile) of asAttr) as list
  
  
set aCount to 1
  
set prevRec to {}
  
set iRange to missing value
  
  
set delRange to 0
  
  
repeat with i in aList
    set tmpCol to (colorStr of i) as string
    
set tmpStr to (stringVal of i) as string
    
set tmpRange to (location of itemRange of i) as integer
    
    
if (tmpCol is not equal to comColStr) and (tmpStr does not end with (return & return)) and ((location of itemRange of i) > ((length of aHeader) – 3)) then –改行コードが2つ連続した場合に同じ色情報になるのでこのように記述(重要)
      set iRange to itemRange of prevRec
      
exit repeat
    else
      set aLoc to (location of itemRange of i) as integer
      
set aLen to (length of itemRange of i) as integer
      
set delRange to delRange + aLoc + aLen
    end if
    
    
set aCount to aCount + 1
    
copy (contents of i) to prevRec
  end repeat
  
  
if iRange = missing value then error "Comment not found "
  
  
set tmpLoc to (location of iRange) + (|length| of iRange)
  
return tmpLoc
end retHeaderCommentRange

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in file File path RTF Spotlight | Tagged 10.13savvy 10.14savvy Script Editor | Leave a comment

sdefの内容を強引に取得する

Posted on 9月 12 by Takaaki Naganoya

指定アプリケーションのsdefの内容を強引に取得するAppleScriptです。

スクリプトエディタをAppleScriptからコントロールして、指定アプリケーションのsdef(AppleScript用語辞書)の内容を取得します。もちろん、AppleScript対応のアプリケーションに限ります。対応/非対応の判定はあらかじめ行なっておいてください。

そもそも、なんでこれが必要になったかといえば、各種AppleScript Libraryの整備のための資料として、既存のAppleScript対応アプリケーションの識別コード(4文字コード)を取得して確認しておきたかったためです。

そこで、まっとうな方法だと、

step 1:対象アプリケーションのInfo.plistの内容を確認してsdefの名称を取得

step 2:アプリケーションバンドル内のsdefを取得

という流れになります。これで済めば処理は非常に短時間に完了します。ファイル処理だけなので。

しかし、実際にやってみると…………標準的な方法でsdefを取得できないアプリケーションがいくつか存在することに気づきます。

(1)Adobe Illustratorなど

バンドル内にsdefが存在しない。動的にsdefを生成しているのでは?

(2)scriptSuite+scriptTerminology

バンドル内にsdefではなく.scriptSuiteファイルと.scriptTerminologyファイルを格納。テキストエディット(TextEdit.app)やスクリプトエディタ(Script Editor.app)などが該当する。

また、一部のアプリケーション(MS-Officeなど)ではsdefファイルのうち一部を外部からincludeしているため、アプリケーションバンドル内のsdefファイルを読んだだけでは完全なsdefが取得できないといった問題もあります。

そこで、この「スクリプトエディタをコントロールしてsdefの内容を取得する」という頭の悪そうな処理が必要になりました。シェルのsdefコマンドを使えばいいんじゃない? という意見も出てきそうですが、現行環境(macOS 10.14.x)でsdefコマンドはうまく動いていないように見えます。

AppleScript名:sdefの内容を強引に取得する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/12
—
–  Copyright © 2019 jp.piyomarusoft, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aPath to (choose file of type "com.apple.application-bundle" default location (path to applications folder) with prompt "Select an application")
set sdefContents to getForceSdefContentsUsingSE2(aPath) of me

on getForceSdefContentsUsingSE2(anAlias)
  try
    tell application id "com.apple.ScriptEditor2"
      open anAlias
      
tell front document
        set dictPath to path
      end tell
    end tell
  on error erM
    return erM
  end try
  
  
  
tell current application
    set aSdef to read dictPath
  end tell
  
  
tell application id "com.apple.ScriptEditor2"
    tell front document
      close without saving
    end tell
  end tell
  
  
return aSdef
end getForceSdefContentsUsingSE2

★Click Here to Open This Script 

Posted in file sdef | Tagged 10.12savvy 10.13savvy 10.14savvy Script Editor | Leave a comment

Script Editor, Script Debuggerから選択範囲の情報を取得

Posted on 8月 19 by Takaaki Naganoya

スクリプトエディタ(Script Editor)およびScript Debuggerの最前面の書類から選択範囲の情報を取得するAppleScriptです。

スクリプトエディタとScript Debuggerで動く共通のツールをAppleScriptで作ってみたら、結果が異なりました。両エディタで同じ範囲を選択してみても、


▲Script Editor上で選択(左)、Script Debugger上で選択(右)

Script Editorでは、character range of selectionを実行すると、{文字開始位置, 文字終了位置}を返してきます。

一方、Script Debuggerでは、character range of selectionを実行すると、{文字開始位置, 選択文字長}を返してきます。

この違いにより、両エディタで異なる結果が得られたのでした。

選択中のテキスト(contents of selection)をそのまま取得して処理するのはよくあるパターンです。選択範囲を数値で取得するケースは(個人的に)あまりありませんでした。

これらのエディタ上で選択中のAppleScriptソースを取得して、そのままコンパイル(構文確認)して変数のみ抽出して変数名の一覧リストが欲しかったのですが、部分的にコンパイル(構文確認)しただけではエラーになる例が多い(ライブラリを呼び出している場合とか)ので、ファイル全体をコンパイル(構文確認)したのちに、エディタ上の選択範囲に該当するデータを抽出するように変更してみました。


▲選択範囲からAppleScript構文色分け情報をもとに変数のみ列挙して返すAppleScriptを実行。このために両エディタ対応を調べていた

AppleScript名:Ecript Editorの選択範囲情報を取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/08/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
tell application "Script Editor"
  tell front document
    set {cStart, cEnd} to character range of selection –{start pos, end pos}
    
return {cStart, cEnd}
    
–> {516, 1334}
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:Script Debuggerの選択範囲情報を取得
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/08/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
tell application "Script Debugger"
  tell front document
    set {cStart, cNums} to character range of selection –{start pos, length}
    
return {cStart, cStart + cNums – 1}
    
–> {516, 1335}
  end tell
end tell

★Click Here to Open This Script 

Posted in list Text | Tagged 10.12savvy 10.13savvy 10.14savvy Scri Script Debugger Script Editor | Leave a comment

選択中のリストのテキスト(多分)をもとにKeynoteの表を作成 v2

Posted on 8月 1 by Takaaki Naganoya

Script Editor上で選択中の1D List(1次元配列)のテキストを評価してリストとして解釈し、それをもとにKeynoteの新規書類上に表を作成するAppleScriptの改良版です。

こんな感じ(↑)に、Script Editor上で1D List(1次元配列)のテキストが存在しているものを、資料化するためにKeynote上で表にすることがあり、その作業を自動化してみました。

スクリプトエディタ上の選択範囲のテキストをrun scriptコマンドで実際に実行(Evalのような使い方)して本物のAppleScriptのリストを作成して処理します。

ここがたいへんにセキュリティホールになりやすいので、実行前にテキストをAppleScriptとして構文確認を行い、危ない構文要素(コマンド類)が入っていないか、AppleScriptの構文的に中途半端でないかチェックを行います。

技術的にはMac OS X 10.4ないし10.5の時代に確立していた内容ではありますが、当時はスクリプトエディタをコントロールして構文色分け情報を取得していたので、macOS 10.10以降でCocoaの機能がAppleScriptから直接利用できるようになって、よりスマートに処理できるようになりました。

Mac OS X 10.4の時代には、plistの情報はテキストで記録されていたので、構文色分け設定を読むのは簡単でした。スクリプトエディタから書式つきテキスト情報(attribute runs)を取得して付け合わせを行っていました。途中でplistの内容がバイナリ化されてplistを読むことが難しくなったので、新規書類に「すべての構文要素が入った最低限度のAppleScript」を転送して構文確認を行い、attribute runsを取得して規定の場所の書式情報を取得することで、特定の構文要素の色分け情報を取得していました(一瞬で新規書類を作成して構文確認し、すぐに破棄するので目には見えない)。

–> Download selectedStrToKeynoteTable (Source AppleScript Bundle with Library)

–> Download selectedStrToKeynoteTableWithCodeSign(AppleScript Applet executable with Code Sign)

ただし、本ScriptをmacOS 10.14上で実行してみていろいろ問題を感じました。まずは、スクリプトエディタ/Script Debugger上で実行する分には何も問題はありません。ここは大事なので明記しておきます。

これ以外の実行環境で実行させると、とたんに首をひねりたくなるような挙動が見られます。Script Menuから実行することを前提に作ってみたわけですが………

普通にScriptとして保存して実行(署名なし、公証なし):初回実行時にオートメーション認証ダイアログが表示されて実行。数回同じScriptを実行すると実行されなくなる(!)

Appletとして保存して実行(署名なし、公証なし):実行時、毎回オートメーション認証ダイアログが表示されて実行。

Appletとして保存して実行(署名あり、公証なし):初回実行時、オートメーション認証ダイアログが表示されて実行。連続して実行するとダイアログ表示なし。しばらく時間を置いて実行するとダイアログ表示される。

macOS 10.14については2か月前から使い始めたので、公証についてもまだうまく行えていません(SD Nortaryで開発者IDが認識されない、、、)。こちら(公証)も試してみるべきなんでしょう。

公証関連については、実際に行っている方、失敗した方の意見をまとめておきたいので、本Blog併設のフォーラムにて(言語は英語でも何語でもOKなので)情報交換させてください。

AppleScript名:選択中のリストのテキスト(多分)をもとにKeynoteの表を作成 v2
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/31
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use dangerAS : script "checkDangerAS"

set aTargMasterSlide to "空白" –This string is *Localized* in Japanese. This is "Blank"

tell application "Script Editor"
  tell front document
    set bText to contents of selection
  end tell
end tell

if bText = "" then return

–指定のテキストをAppleScriptとして評価し、指定の構文要素に該当するものが含まれているかどうかチェック
set dRes to chkTargLexicalElementsFromCompiledScriptAttribute(bText, {9, 14}) of dangerAS
if dRes = missing value then
  –The selected text contains AppleScript lexical error
  
display dialog "選択中のテキストにAppleScriptの構文エラーが検出されました" default answer bText with title "Error" with icon 2
  
return
end if

if dRes = true then
  –The selected text contain danger AppleScript lexical element (maybe it is any command)
  
display dialog "選択中のテキストは実行に危険な文字列(AppleScriptコマンド)を含んでいるため、処理しませんでした" default answer bText with title "Error" with icon 2
  
return
end if

try
  set aRes to run script bText –Danger!! Take Care of.
  
set aClass to class of aRes
on error
  –The Evaluation error (some AppleScript lexical error)
  
display dialog "The contents of clipboard seems not to be an AppleScript list but " & (aClass as string) & return & bText with title "Error (1)" with icon 2
  
return
end try

if aClass is not equal to list then
  –The Evaluated result is not list
  
display dialog "The contents of clipboard seems not to be an AppleScript list but " & (aClass as string) & return & bText with title "Error (2)" with icon 2
  
return
end if

set aLen to length of aRes
set aDim to getDimension given tArray:aRes
if aDim > 1 then
  –Check List’s dimension (the taeget dimension is 1)
  
display dialog "選択中のテキストを評価したリスト(配列)の次元数が1ではなかったので、処理しませんでした" default answer bText with title "Dimension Error(3)" with icon 2
  
return
end if

tell application "Keynote"
  activate
  
set aDoc to (make new document with properties {document theme:theme "ホワイト", width:1024, height:768}) — –This string is *Localized* in Japanese. This is "White"
  
  
tell aDoc
    set masList to name of every master slide
    
if aTargMasterSlide is not in masList then return –多分ないと思うが、作成予定のマスタースライドが現在有効でない場合に処理打ち切り
    
    
set base slide of current slide to master slide aTargMasterSlide
    
    
tell current slide
      set aTable to make new table with properties {header column count:0, header row count:1, row count:2, column count:aLen, name:"Test Table"}
      
      
tell aTable
        repeat with y from 1 to 1
          tell row y
            repeat with x from 1 to aLen
              tell cell x
                set value to (item x of aRes) as string
              end tell
            end repeat
          end tell
        end repeat
      end tell
      
    end tell
  end tell
end tell

–指定Listの次元を再帰で取得する
on getDimension given tArray:aList as list : {}, curDim:aNum as integer : 1
  set anItem to contents of first item of aList
  
set aClass to class of anItem
  
  
if aClass = list then
    set aNum to aNum + 1
    
set aRes to getDimension given tArray:anItem, curDim:aNum
  else
    return aNum
  end if
end getDimension

★Click Here to Open This Script 

Posted in Code Sign Color list Notarization OSA regexp | Tagged 10.12savvy 10.13savvy 10.14savvy Keynote Script Editor | Leave a comment

選択中のリストのテキスト(多分)をもとにKeynoteの表を作成

Posted on 7月 31 by Takaaki Naganoya

Script Editor上で選択中の1D List(1次元配列)のテキストを評価してリストとして解釈し、それをもとにKeynoteの新規書類上に表を作成するAppleScriptです。

こんな感じ(↑)に、Script Editor上で1D List(1次元配列)のテキストが存在しているものを、資料化するためにKeynote上で表にすることがありますが、これが個人的に超絶かったるいです。

きれいにデータになっているものを、表のセルに細切れにして突っ込む作業がかったるいので、おそらくそれを手動で行う数倍の時間をかけてAppleScriptで自動化しておきました。

(1)Script Editor上でListの箇所を選択しておく
(2)Script Menuに入れておいた本Scriptを呼び出す
(3)Keynoteで新規書類を作成し、1ページ目に表を新規作成し、(1)の内容を1行目に代入

という動作を行います。上記のとおり、Script Menuに入れて呼び出すことを前提にしています。もし、そうでなければ当該部分をコピーしておいて、クリップボード経由で受け取るようにしてみてください。

当初は本Scriptもそういう構造になっていましたが、選択部分をコピーするのを忘れることが多いため、選択箇所から取得するように変更しました。

本Scriptは自分自身で使うことを前提に作ったため(本Blogまるごとそんなもんですが)、run scriptコマンドで文字列をAppleScriptとして評価して実行して結果を取得するという、ひじょーーーーーにセキュリティホールになりやすい処理を行っています。

本来、取得した文字列をAppleScriptとして評価して、構文要素的に「コマンド類」が入っていないか(とくにdo shell script)を評価する必要があると思います。その上で、もしもコマンド類が入っていた場合にはユーザーに再考を促すようにダイアログを表示するなどの処理を行うのがまっとうなやりかたでしょう。

このあたり、ものすごくラフに作ったので、利用はあくまで自己責任で行ってください(本Blogまるごとそんなもんですが)。

AppleScript名:選択中のリストのテキスト(多分)をもとにKeynoteの表を作成
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/31
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aTargMasterSlide to "空白" –This string is *Localized* in Japanese. This is "Blank"

tell application "Script Editor"
  tell front document
    set bText to contents of selection
  end tell
end tell

if bText = "" then return

try
  set aRes to run script bText –Danger!! Take Care of.
  
set aClass to class of aRes
on error
  display dialog "The contents of clipboard seems not to be an AppleScript list (1)." with title "Error"
  
return
end try

if aClass is not equal to list then
  display dialog "The contents of clipboard seems not to be an AppleScript list (2)." with title "Error"
  
return
end if

set aLen to length of aRes

tell application "Keynote"
  activate
  
set aDoc to (make new document with properties {document theme:theme "ホワイト", width:1024, height:768}) — –This string is *Localized* in Japanese. This is "White"
  
  
tell aDoc
    set masList to name of every master slide
    
if aTargMasterSlide is not in masList then return –多分ないと思うが、作成予定のマスタースライドが現在有効でない場合に処理打ち切り
    
    
set base slide of current slide to master slide aTargMasterSlide
    
    
tell current slide
      set aTable to make new table with properties {header column count:0, header row count:1, row count:2, column count:aLen, name:"Test Table"}
      
      
tell aTable
        repeat with y from 1 to 1
          tell row y
            repeat with x from 1 to aLen
              tell cell x
                set value to (item x of aRes) as string
              end tell
            end repeat
          end tell
        end repeat
      end tell
      
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in list | Tagged 10.12savvy 10.13savvy 10.14savvy Keynote Script Editor | Leave a comment

指定のAppleScriptテキストを構文確認して変数・プロパティ、サブルーチン名部分のみを取得して置換

Posted on 7月 17 by Takaaki Naganoya

指定のAppleScriptのテキストを構文確認して、構文的に「変数・プロパティ、サブルーチン名」部分に該当する部分のテキストを取得して、目的のテキストに差し替えるAppleScriptです。

Script Debugger上の生産性を向上させるために書いたものです。Script Debuggerはいわゆる「デバッグ」段階では役に立ちますが、快適にScriptを書くための機能はほとんどありません。

いわゆる、ブレークポイントの設定、プログラムのステップ実行、ステップ実行時の変数値のリアルタイムモニタリング、という「デバッガ」の機能は持っていますが、巨大なScriptを書いたときの特定のサブルーチンを前回実行時に指定したパラメータで再実行して結果を比較といった機能は備えていません(切実にほしー。自分で作りたいぐらい)。

とくに、記述中のAppleScriptの選択部分の構文要素を検出して特定の構文要素(コメントとか変数名とか)についてのみ処理を行うような機能が用意されていない点が残念です(スクリプトエディタ用は数百本書いて使っているので)。

とりわけ、プロパティ文の記述などは毎回同じようなものをコピペで足すだけなので、書き足すのがかったるいと思っていました。

そこで、編集中のAppleScriptの範囲から構文要素を考慮して変数名だけ書き換えてくれるといった機能を足してみました。

テキストで与えたAppleScript(実際にはScript Debuggerの選択範囲から取得)を

	property textList : {}

実際にメモリ上でコンパイル(構文確認)して、書式付きテキストを取得し、そこから構文色分け設定に基づいて該当する構文要素をピックアップ。該当する構文要素の箇所を置換します。

--> textList

# 置換部分だけ文字置換にしていますが、そこはそれ

	property boundsList : {}

–> Download repLexicalValStr as AppleScript bundle doc with library

例によって、AppleScriptの構文色分け設定の値を読み取って処理しているので、構文要素間で色の値(RGB値)で重複があると(or 値が近すぎると)エラーになります。また、先日報告された「RGB以外の色空間の色」で設定してある場合でもRGB色空間に色データを変換して処理しています(まさかCMYKとかグレースケールで色設定しているユーザーがいるとは思わなかったわー)。

スクリプトエディタ、Script Debugger上での動作を確認していますが、Applet書き出ししたときにまだ謎なメッセージを出すようです。何か、明示的にメインスレッドで実行する必要のあるものがあったでしょうか。


▲Applet書き出しして、実行した際に、ちょっと謎なメッセージが出る時がある(macOS 10.14.5)。vectorってなんだよ?


▲Applet実行時にエラーが出たあとに、再度実行したときにこんな謎なメッセージが出る(macOS 10.14.5)

AppleScript名:指定のAppleScriptテキストを構文確認して変数・プロパティ、サブルーチン名部分のみを取得して置換.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/04
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use framework "AppKit"
use framework "OSAKit"
use attrLib : script "asAttrRecLib"

property NSArray : a reference to current application’s NSArray
property OSANull : a reference to current application’s OSANull
property NSString : a reference to current application’s NSString
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSUnarchiver : a reference to current application’s NSUnarchiver
property OSALanguage : a reference to current application’s OSALanguage
property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property OSALanguageInstance : a reference to current application’s OSALanguageInstance

script spd
  property fArray : {}
  
property outList : {}
  
property resStr : {}
end script

on run
  set theSource to "  property textList : {}"
  
set repValstr to "boundsList"
  
  
set pureValStr to retTargStrFromCompiledScriptAttribute(theSource, 7) of me –Variables and Sub-routine names
  
–> "textList"
  
  
set newLine to repChar(theSource, pureValStr, repValstr) of me
  
–> "  property boundsList : {}"
  
  
display dialog newLine
end run

–AppleScriptのソーステキストをコンパイルして、
on retTargStrFromCompiledScriptAttribute(theSource as string, colSettingOrder as integer)
  if colSettingOrder < 1 or colSettingOrder > 18 then error ("Lexical element index range error (safe range: 1….18. You set " & colSettingOrder as string) & ")"
  
  
–AppleScriptの構文色分け情報を取得
  
set ccRes to getAppleScriptSourceColors() of me
  
set cRes to chkASLexicalFormatColorConfliction(ccRes) of me –構文色分けの重複色チェック
  
if cRes = false then error "There is some duplicate(s) color among AppleScript’s lexical color settings"
  
  
–検索用の色情報を作成
  
set commentCol to contents of item colSettingOrder of ccRes –Variable and Sub-routine name
  
set searchVal to (redValue of commentCol as string) & " " & (greenValue of commentCol as string) & " " & (blueValue of commentCol as string) –for filtering
  
  
–与えられたテキストをAppleScriptとして評価し構文色分け情報をもとにStyle Runs的なDictionary化して返す
  
set aRitch to compileASSourcetextAndReturnStyledText(theSource) of me
  
  
  
–書式付きテキストからstyle runs的な書式リストを作成
  
set anAttrList to getAttributeRunsFromAttrString(aRitch) of attrLib
  
–>
  
(*
(NSArray) {
  {
    fontSize:12.0,
    stringVal:"set",
    colorVal:{
      14,
      62,
      251
    },
    fontName:"Osaka",
    itemIndex:1,
    colorStr:"14 62 251"
  },…..
*)
  
  
set tmp1Array to NSArray’s arrayWithArray:anAttrList
  
  
–コメント以外の要素をピックアップ 文字と色で抽出
  
–set thePred2 to NSPredicate’s predicateWithFormat_("colorStr != %@ && stringVal != %@", searchVal, (return & return & return & return))
  
set thePred2 to NSPredicate’s predicateWithFormat_("colorStr == %@", searchVal)
  
set (fArray of spd) to ((tmp1Array’s filteredArrayUsingPredicate:thePred2)’s valueForKeyPath:"itemIndex") as list
  
–> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84}
  
  
–アイテム番号のリストをもとに、ピックアップ対象のアイテムだけを再連結
  
set (outList of spd) to {}
  
repeat with i in (fArray of spd)
    set aStr to ((item i of anAttrList)’s stringVal) as string
    
set the end of (outList of spd) to aStr
  end repeat
  
  
set (resStr of spd) to retDelimedText((outList of spd), return) of me
  
  
return (resStr of spd)
end retTargStrFromCompiledScriptAttribute

on retDelimedText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retDelimedText

——-

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceColors()
  — get the plist info as a dictionary
  
set thePath to NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set colList to {}
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 255) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set aColRec to {redValue:rVal, greenValue:gVal, blueValue:bVal, fontName:aFontName, fontSize:aFontSize}
    
    
set the end of colList to aColRec
  end repeat
  
  
return colList
end getAppleScriptSourceColors

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceNSColorsDict()
  — get the plist info as a dictionary
  
set thePath to NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set aDict to NSMutableDictionary’s alloc()’s init()
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 255) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set colIndStr to (rVal as string) & " " & (gVal as string) & " " & (bVal as string)
    
set tmpColDat to {numList:{rVal, gVal, bVal}, strInd:colIndStr}
    
–(aDict’s addObject:tmpColDat forKey:theColor)
    (
aDict’s addObject:{rVal, gVal, bVal} forKey:theColor)
  end repeat
  
  
return aDict
end getAppleScriptSourceNSColorsDict

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aSpace to (aCol’s colorSpaceName()) as string
  
–set aSpace to (aCol’s type()) as integer
  
  
if aSpace is in {"NSDeviceRGBColorSpace", "NSCalibratedRGBColorSpace"} then
    copy aCol to cCol
  else
    –RGB以外の色空間の色は、RGBに変換
    
–CMYKとグレースケールは同一メソッドでRGBに変換できることを確認済み
    
set cCol to aCol’s colorUsingColorSpaceName:"NSCalibratedRGBColorSpace"
    
if cCol = missing value then error "Color Space Conversion Error (" & aSpace & " to NSCalibratedRGBColorSpace)"
  end if
  
  
set aRed to round ((cCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((cCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((cCol’s blueComponent()) * aMAX) rounding as taught in school
  
  
if aRed > aMAX then set aRed to aMAX
  
if aGreen > aMAX then set aGreen to aMAX
  
if aBlue > aMAX then set aBlue to aMAX
  
  
return {aRed, aGreen, aBlue} as list
end retColListFromNSColor

–AS書式で配色に重複がないかどうかチェック
on chkASLexicalFormatColorConfliction(aList)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set bList to (anArray’s valueForKeyPath:"redValue.stringValue") as list
  
set cList to (anArray’s valueForKeyPath:"greenValue.stringValue") as list
  
set dList to (anArray’s valueForKeyPath:"blueValue.stringValue") as list
  
  
set colStrList to {}
  
repeat with i from 1 to (length of bList)
    set bItem to contents of item i of bList
    
set cItem to contents of item i of cList
    
set dItem to contents of item i of dList
    
set the end of colStrList to bItem & " " & cItem & " " & dItem
  end repeat
  
  
set aRes to returnDuplicatesOnly(colStrList) of me
  
  
if aRes is equal to {} then
    return true –重複が存在しなかった場合
  else
    return false –重複があった場合
  end if
end chkASLexicalFormatColorConfliction

on returnDuplicatesOnly(aList as list)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bList to (aSet’s allObjects()) as list
  
  
set dupList to {}
  
repeat with i in bList
    set aRes to (aSet’s countForObject:i)
    
if aRes > 1 then
      set the end of dupList to (contents of i)
    end if
  end repeat
  
  
return dupList
end returnDuplicatesOnly

–テキスト形式のAppleScriptをコンパイルして書式付きテキスト(NSAttributedString)を返す
on compileASSourcetextAndReturnStyledText(theSource)
  — create a new AppleScript instance
  
set anOSALanguageInstance to OSALanguage’s languageForName:"AppleScript"
  
  
set theScript to OSAScript’s alloc()’s initWithSource:theSource fromURL:(missing value) languageInstance:anOSALanguageInstance usingStorageOptions:(OSANull)
  
set {theResult, theError} to theScript’s compileAndReturnError:(reference)
  
  
if theResult as boolean is false then
    — handle error
    
error "Compile Error"
  else
    set styledSourceText to theScript’s richTextSource()
  end if
  
  
return styledSourceText
end compileASSourcetextAndReturnStyledText

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in Color OSA Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSCountedSet NSDictionary NSMutableArray NSMutableDictionary NSPredicate NSString NSUnarchiver OSALanguage OSALanguageInstance OSANull OSAScript Script Debugger Script Editor | Leave a comment

as anything

Posted on 4月 3 by Takaaki Naganoya

as anythingについてまとまった情報がなかったので、まとめておきました。結論めいたものはとくになく、ただ、手持ちの情報を並べてみただけの内容なのでご容赦ください。「これはこうあるべき!」とかいう提言とかは一切ありません。

割と最近なas anythingとの遭遇

つい最近まで、ながらく存在自体を知らなかったのが、このanythingという予約語です。

AppleScriptの用語辞書をASObjC Explorer 4で書いて試していたとき、パラメータの型に「any」というものが存在していることには気づいていましたが、それでも「anything」という予約語があることには気づきませんでした。

本格的に知ったのは、applescript-stdlibを漁っていたときです。

同ライブラリはトリッキーなScriptの記述方法の見本市みたいになっていて、内容自体の完全理解についてはサジを投げた状態でしたが、見たことのない記述にいろいろ行き当たりました(もっと読みやすく書いてほしかった ^ー^;;)。

delegateの呼び出し先にscriptオブジェクト内部のハンドラを指定したりと、「そんな書き方できるんだ。やらんけど」と、まるで古文書をひもとくような感覚(これを見ていると、こーゆー風にblocks構文をAppleScriptでも記述できればいいのに、と思います)。

そこで見つけた「as anything」表記。これは一体なんなんでしょう?

いい加減に使えてとても便利なas anything

実際に動かしてみたところ、「あーー、この機能昔から欲しかったわー」という内容でした。anonymous classとでもいうのでしょうか。castするときにclass名を指定しないワイルドカードなclassと理解しました。

「as anything」でAppleScriptのデータ型はそのまま、AppleScriptのデータ型にcast可能なCocoaのデータはAppleScriptのデータ型に変換。変換不能なCocoaのデータ型についてはそのまま、という処理をしてくれます。

# ただし要素数が1つのNSArrayをas anythingでAppleScript Objetに変換すると、listではなく中身のデータが取り出されてしまう(型が合わなくなる)ので、注意が必要とのこと(Thanks Shane!)
# なので、あらかじめNSArrayが返ってくることがわかっている場合には、as list。NSArrayか他のデータ(missing valueとか)が返ってくる場合には、as {missing value, list} などとするとよいでしょう

BridgePlus的にいえば、「ASify without BridgePlus」といったところでしょうか。CocoaとAppleScriptの間でデータをやりとりするのにえっらく都合がよかったのです。かくして、「as anything」を愛用しまくるスタイルが確立。

ただ、anythingは言語仕様のはざまで埋もれかけていた「枝葉末節」の中の一番の「枝葉」ともいうべき、言語仕様の極北。AppleScript Language Guideにも記載されていないほどの枝葉仕様。

AppleScriptObjCのプログラム中に書くと、予約語が用意されていないためか「as anything」が「as list of string or string」などと解釈されてしまいます(動作自体はanythingと同じ)。

anythingについては、Apple側がわりとぞんざいに仕様を放置していたきらいがあります。問題が起こらないかぎり放っておこう、と。as «class isot»のようにある日突然(Mac OS X 10.5で)消えてなくなったりしないかちょっと不安に感じたこともありましたが、一応まがりなりにも予約語が割り振られているので(生Apple Eventを記述させられないので)、そんなに簡単に消えないとは思います。

主要開発環境で足並みそろわず

雑に放置していたAppleに対して、この問題に正面から向き合っていた集団が存在します。それが、Script DebuggerのメーカーであるLate Night Softwareです。

macOS 10.12や10.13上ではあいかわらずASOCのプログラムでは「as anything」が「as list of string or string」と解釈されますが、macOS 10.14で対応に差が出ました。

Script Debugger上では「anything」が「any」と解釈され、スクリプトエディタ上では「anything」と解釈されます。

macOS 10.14上でのスクリプトエディタで「as anything」が「as list of string or string」のように化けないのはいいと思います。ただ、Script DebuggerのメーカーであるLate Night Software側ではこれに「any」という別の予約語を割り振ったようで、、、、足並みがそろっていません。

一応、macOS 10.14上のスクリプトエディタv2.11上で「as anything」と記述したScriptを、同じくmacOS 10.14上のScript Debuggerに持っていくと「as any」と表示されます。いったん中間コードにコンパイルされたものは問題がないようです。

問題になるのは、Blogなどに掲載されている文字の状態のAppleScriptで、anythingについてはコンパイル(構文確認)時に気をつける必要がありそうです(メイン環境が10.14に移行していないのでちょっとまだ他人事)。

困ったときの古文書だより

一応、現代AppleScriptのルーツの資料とされている「AppleScriptLanguageGuide 1.3.7」(1999/5/5)のPDFを確認してみると、けっこう悩ましい内容が記述されています。

自分はanythingをclassか何かだと思っていたのですが、そこには定数(constants)だと書かれています。AppleScript version 1.3.7のころには、missing value(不定値)みたいな運用が行われていたようです。

AppleのEngineering Teamの見解は?

匿名希望の方がApple Engineering Teamに問い合わせしたところ「そんなマイナーな予約語は使うな」という返答であったとか。その一方でmacOS 10.14で「anything」の「list or list of string」への解釈化けが抑止されたりしているわけで、いまひとつわかりにくいというのが現状です。

Posted in OSA | Tagged 10.12savvy 10.13savvy 10.14savvy Script Debugger Script Editor | Leave a comment

オープン中のScriptをすべて書き換える

Posted on 1月 19 by Takaaki Naganoya

Script Editorでオープン中のAppleScript書類に対してすべて文字置換を行って、変更があれば保存を行うAppleScriptです。

Xcodeで作成するAppleScriptアプリケーションのプロジェクトで、サブScriptをZipアーカイブに入れ、展開しては順次呼び出すようにしていました。

サブスクリプト側とメインのAppleScriptアプリケーション側はUser Defaultsを介してパラメータのやりとりを行っていますが、Bundle IDの大文字/小文字の記述ミスからうまくパラメータの受け渡しが行えませんでした。

そこで、すべてのサブスクリプトを書き換えることにしたのですが、順次オープンして書き換えたのでは、(サブスクリプトの数が多すぎて)手間がかかり書き換えミスの可能性も否定できません。テキストエディタでは、BBEditなどで指定ディレクトリ以下のテキストファイルに対してすべて処理する機能が実装されていますが、Script DebuggerなどAppleScriptの編集プログラムにその機能が実装されているのは見たことがありません。

処理内容も簡単なので、その場で作ってしまいました。

なお、Script EditorをコントロールするAppleScriptは、大事をとってScript Editor以外のプログラム上で実行することが推奨されます。Script DebuggerかmacOS標準搭載のスクリプトメニューです。

Mac OS X 10.4の頃までは、Script Editor上でScript EditorをコントロールするAppleScriptを書いて実行するといろいろ不具合が出ていました。Mac OS X 10.5以降でずいぶん改善された印象があります。

本AppleScriptのような処理内容では、単なる文字置換ではなく、指定の構文要素(文字定数など)に該当するものがあれば置換を行うなど、より高度な処理を行うものに書き換えていくとよいでしょう。さすがに変数名の置換は作って使っていますが、文字定数やコメント内容を対象にするものを用意しておいてもいいように思えます。

AppleScript名:オープン中のScriptをすべて書き換える.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/01/19
—
–  Copyright © 2019 MyCompanyName, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set origStr to "jp.piyomarusoft.samplebundleid"
set toStr to "jp.piyomarusoft.sampleBundleID"

tell application "Script Editor"
  set dList to every document
  
  
repeat with i in dList
    set j to contents of i
    
    
tell j
      
      
set aCon to text of it
      
set bCon to repChar(aCon, origStr, toStr) of me
      
      
considering case
        if aCon is not equal to bCon then
          set text of it to bCon
          
save
        end if
      end considering
      
    end tell
    
  end repeat
end tell

–文字置換ルーチン
on repChar(origText as string, targStr as string, repStr as string)
  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

★Click Here to Open This Script 

Posted in Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Script Editor | Leave a comment

ASOCからclass名を抽出してpropertyとして展開 v4

Posted on 8月 5, 2018 by Takaaki Naganoya

スクリプトエディタの最前面のドキュメントを解釈して、CocoaのClass名とEnumを抽出してpropertyに展開して、新規書類に展開するAppleScriptです。

いわゆる「AppleScriptの内容を解析して書き換える」AppleScriptです。


▲左が処理前、右が本Scriptで処理を行ったAppleScript

Cocoa Classのチェックのために、実際にNSClassFromStringでオブジェクトを作れるかどうかチェックしています。Enumについては、ヘッダーファイルを検索してチェックを行っています。そのため、本AppleScriptは実行環境にXcodeがインストールされていないとEnumチェックが行えません。

前バージョンではXcodeのアプリケーションバンドル以下に存在しているヘッダーファイルのパスを計算するときにXcodeが起動されていましたが、本バージョンではXcodeが起動しないように修正しました。

また、propertyを展開するときに、プロポーショナルフォントで画面描画した際の幅を実際に計算して、文字の描画幅のピクセル数順にソートしています。

本AppleScriptはEnumの確認のために全ヘッダーファイルを走査しているため、この部分で少々処理時間がかかります。次にバージョンアップすることがあれば、このCocoa ClassとEnumの確認をキャッシュするようにして、二度目以降は同じ文字列の問い合わせを行わないようにしたいところです。

AppleScript名:ASOCからclass名を抽出してpropertyとして展開 v4
— Created 2017-08-12 by Takaaki Naganoya
— Modified 2018-08-05 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "OSAKit"

property NSFont : a reference to current application’s NSFont
property NSData : a reference to current application’s NSData
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSBundle : a reference to current application’s NSBundle
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSTextView : a reference to current application’s NSTextView
property NSDictionary : a reference to current application’s NSDictionary
property NSFileManager : a reference to current application’s NSFileManager
property OSALanguage : a reference to current application’s OSALanguage
property NSCountedSet : a reference to current application’s NSCountedSet
property OSAScriptView : a reference to current application’s OSAScriptView
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSAttributedString : a reference to current application’s NSAttributedString
property OSAScriptController : a reference to current application’s OSAScriptController
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSKernAttributeName : a reference to current application’s NSKernAttributeName
property OSALanguageInstance : a reference to current application’s OSALanguageInstance
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSMutableParagraphStyle : a reference to current application’s NSMutableParagraphStyle
property NSLigatureAttributeName : a reference to current application’s NSLigatureAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSUnderlineStyleAttributeName : a reference to current application’s NSUnderlineStyleAttributeName
property NSParagraphStyleAttributeName : a reference to current application’s NSParagraphStyleAttributeName
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName

set aCon to getFrontmostSEContents() of me
set aaList to paragraphs of aCon

set aList to retPropertiesClass(aCon) of me
set bList to retCurrentApplicationsClass(aCon) of me

–置換してはいけないリスト。text encoding系はenumの桁数が足りなくてpropertyに代入できない。Cのメソッドは代入しても効かない
set cList to {"\"", "\",", ",", "(", ")", "NSMakeRange", "NSMakePoint", "NSMakeRect", "NSMakeSize", "NSHomeDirectory", "NSUTF16BigEndianStringEncoding", "NSUTF16LittleEndianStringEncoding", "MKMapPointMake", "NSNotFound", "CGRectZero", "NSClassFromString"}

set aSet to current application’s NSMutableSet’s setWithArray:aList –property宣言文の一覧
set bSet to current application’s NSMutableSet’s setWithArray:bList –script中のcurrent application文のクラス
set cSet to current application’s NSMutableSet’s setWithArray:cList

bSet’s minusSet:aSet –current applicationで指定したクラスで、property宣言していないものを計算
bSet’s minusSet:cSet –置換禁止リスト

set dList to bSet’s allObjects() as list

–Cocoa Class, Cocoa Enum Check
set ddList to {}
repeat with i in dList
  set j to (contents of i) as string
  
  
–Cocoa Class Check
  
set fRes to searchClassInFrameworks(j) of me
  
if fRes = false then
    –Cocoa Eum Check
    
set fRes to searchEnumFromHeaderFiles(j) of me
  end if
  
  
if fRes is not in {false, {}} then
    if j is not in cList then
      if j does not contain "(" then
        set the end of ddList to j
      end if
    end if
  end if
end repeat

–Scriptの本文を書き換える
repeat with i in ddList
  set j to contents of i
  
set tmpStr to "current application’s " & j
  
set aCon to repChar(aCon, tmpStr, " " & j) of me
end repeat

–挿入部分のテキストを組み立てる
set repStr to return
repeat with i in ddList
  set j to contents of i
  
set repStr to repStr & "property " & j & " : a reference to current application’s " & j & return
end repeat
set repStr to repStr & return

–AppleScriptソース文字列からAttributed Stringを生成して返す
set anAttrStr to compileASandReturnAttributedString(repStr) of me

–Attributed StringからAttribute Runsに似たデータを作成する
set attrList to getAttributeRunsFromAttrString(anAttrStr) of me
set anArray to (NSArray’s arrayWithArray:attrList)’s valueForKeyPath:"fontName"
set aFontList to (countItemsByItsAppearance(anArray) of me)
set aFontName to theName of first item of aFontList

–クリップボードから取得した文字データについて処理
set aList to paragraphs of repStr –行ごとにparseしてlist化
set bList to {}
repeat with i in aList
  set j to contents of i
  
if j ≠ {} then
    set jList to words of j
    
if jList ≠ {} then
      if contents of first item of jList = "property" then
        set curLabel to contents of second item of jList
        
        
–行をAttributed Stringとして組み立てて、画面描画時の仕上がりサイズを取得
        
set anAssrStr to makeRTFfromParameters(j, aFontName, 16, -2, 16) of me
        
set aSize to anAssrStr’s |size|() –画面描画時のサイズを取得
        
        
if class of aSize = record then
          set attrStrWidth to width of aSize
          
set attrStrHeight to height of aSize
        else if class of aSize = list then –macOS 10.13.xのバグ回避
          copy aSize to {attrStrWidth, attrStrHeight}
        end if
        
        
set the end of bList to {aLabel:curLabel, aCon:j, aWidth:attrStrWidth}
      end if
    end if
  end if
end repeat

if bList = {} then
  display dialog "Error" buttons {"OK"} default button 1
  
return
end if

–複数キーでソート(書式つきテキストの仕上がりサイズ幅、文字コード順でソート)
set aArray to NSArray’s arrayWithArray:bList
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:"aWidth" ascending:true
set desc2 to NSSortDescriptor’s sortDescriptorWithKey:"aLabel" ascending:true selector:"localizedCaseInsensitiveCompare:"
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}

–ソートしたlist of recordからaCon(元のproperty宣言行そのもの)を一括で取り出す
set dArray to (NSMutableArray’s arrayWithArray:bArray)’s valueForKeyPath:"aCon"

–listをデリミタつきのテキストに
set dStr to retStrFromArrayWithDelimiter(dArray, return) of me
set dStr to return & dStr & return & return

set aInsPoint to getFirstInsertionPoint(aCon) of me

tell application "Script Editor"
  set aDoc to make new document
  
tell front document
    set contents to aCon
    
set selection to paragraph aInsPoint
    
set contents of selection to the dStr
    
    
try
      compile
    end try
  end tell
end tell

on getFirstInsertionPoint(aCon)
  set aList to paragraphs of aCon
  
set aCount to 1
  
repeat with i in aList
    set j to contents of i
    
if j = "" then
      exit repeat
    end if
    
set aCount to aCount + 1
  end repeat
  
  
return aCount
end getFirstInsertionPoint

on retPropertiesClass(aCon)
  set resList to {}
  
set regStr to "(property .*?:)"
  
set aRes to my findPattern:regStr inString:aCon capturing:1
  
  
repeat with i in aRes
    set j to first item of (paragraphs of i)
    
    
–正規表現もどきで取り出してみた(ぜんぜん改良の余地がある)
    
set j1 to repChar(j, "current application’s ", "") of me
    
set j2 to repChar(j1, "property", "") of me
    
set j3 to repChar(j2, ":", "") of me
    
set j4 to repChar(j3, " ", "") of me
    
    
set the end of resList to j4
  end repeat
  
  
set res2List to uniquify1DList(resList, false) of me
  
return res2List
end retPropertiesClass

on retCurrentApplicationsClass(aCon)
  set resList to {}
  
set regStr to "(current application’s .*? )"
  
set aRes to my findPattern:regStr inString:aCon capturing:1
  
  
repeat with i in aRes
    set j to first item of (paragraphs of i)
    
    
–正規表現もどきで取り出してみた(ぜんぜん改良の余地がある)    
    
set j1 to repChar(j, "current application’s ", "") of me
    
set j2 to repChar(j1, "’s ", "") of me
    
set j3 to repChar(j2, ")", "") of me
    
set j4 to repChar(j3, "}", "") of me
    
set j5 to repChar(j4, "}", "") of me
    
set j6 to repChar(j5, " ", "") of me
    
    
set the end of resList to j6
  end repeat
  
  
set res2List to uniquify1DList(resList, false) of me
  
return res2List
end retCurrentApplicationsClass

on getFrontmostSEContents()
  tell application "Script Editor"
    set docCount to count every document
    
if docCount = 0 then error "No Document"
    
tell front document
      return contents
    end tell
  end tell
end getFrontmostSEContents

on replaceThis:thePattern inString:theString usingThis:theTemplate
  set theOptions to ((current application’s NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application’s NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to current application’s NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theResult to theRegEx’s stringByReplacingMatchesInString:theString options:0 range:{location:0, |length|:length of theString} withTemplate:theTemplate
  
return theResult as text
end replaceThis:inString:usingThis:

on findPattern:thePattern inString:theString
  set theOptions to ((current application’s NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application’s NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to current application’s NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list — so we can loop through
  
set theResult to {} — we will add to this
  
set theNSString to current application’s NSString’s stringWithString:theString
  
repeat with i from 1 to count of items of theFinds
    set theRange to (item i of theFinds)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as string
  end repeat
  
return theResult
end findPattern:inString:

on findPattern:thePattern inString:theString capturing:n
  set theOptions to ((current application’s NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application’s NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to current application’s NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list — so we can loop through
  
set theResult to {} — we will add to this
  
set theNSString to current application’s NSString’s stringWithString:theString
  
repeat with i from 1 to count of items of theFinds
    set oneFind to (item i of theFinds)
    
if (oneFind’s numberOfRanges()) as integer < (n + 1) then
      set end of theResult to missing value
    else
      set theRange to (oneFind’s rangeAtIndex:n)
      
set end of theResult to (theNSString’s substringWithRange:theRange) as string
    end if
  end repeat
  
return theResult
end findPattern:inString:capturing:

–文字置換
on repChar(aStr, targStr, repStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:targStr withString:repStr
  
return bString as string
end repChar

–1D/2D Listをユニーク化
on uniquify1DList(theList as list, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquify1DList

–指定クラスがいずれかのCocoa Frameworkに所属しているかを検索
on searchClassInFrameworks(aTarget)
  set aClass to current application’s NSClassFromString(aTarget)
  
if aClass = missing value then return false
  
set theComponenents to (NSBundle’s bundleForClass:aClass)’s bundleURL’s pathComponents()
  
set thePred to NSPredicate’s predicateWithFormat:"pathExtension == ’framework’"
  
set aRes to (theComponenents’s filteredArrayUsingPredicate:thePred)’s firstObject() as list of string or string
  
return aRes
end searchClassInFrameworks

–指定文字列がどこかのCocoa FrameworkのEnumとして定義されていないかチェック
on searchEnumFromHeaderFiles(targString)
  set aClass to current application’s NSClassFromString(targString)
  
if aClass is not equal to missing value then return false
  
  
set dPath to retAppAbusolutePathFromBundleID("com.apple.dt.Xcode") of me
  
set aFol to dPath & "/Contents/Developer/Platforms/MacOSX.platform/" & "Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" –ルーチンの仕様変更によりパス表記(トップ)変更
  
  
set bList to retFullPathWithinAFolderWithRecursiveFilterByExt(aFol, "h") of me
  
set matchedList to {}
  
  
repeat with i in bList
    set j to contents of i
    
    
set aStr to (NSString’s stringWithContentsOfFile:j encoding:NSUTF8StringEncoding |error|:(missing value))
    
if aStr ≠ missing value then
      set aRange to (aStr’s rangeOfString:targString)
      
      
if aRange’s location() ≠ current application’s NSNotFound and (aRange’s location()) < 9.99999999E+8 then
        set tmpStr to (current application’s NSString’s stringWithString:j)
        
set pathList to tmpStr’s pathComponents()
        
set thePred to (current application’s NSPredicate’s predicateWithFormat:"pathExtension == ’framework’")
        
set aRes to (pathList’s filteredArrayUsingPredicate:thePred)’s firstObject() as text
        
set the end of matchedList to aRes
      end if
      
    end if
  end repeat
  
  
set aArray to current application’s NSArray’s arrayWithArray:matchedList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end searchEnumFromHeaderFiles

–指定フォルダ以下のすべてのファイルを再帰で取得(拡張子で絞り込み)
on retFullPathWithinAFolderWithRecursiveFilterByExt(aFol, aExt)
  set anArray to NSMutableArray’s array()
  
set aPath to NSString’s stringWithString:aFol
  
set dirEnum to NSFileManager’s defaultManager()’s enumeratorAtPath:aPath
  
  
repeat
    set aName to (dirEnum’s nextObject())
    
if aName = missing value then exit repeat
    
set aFullPath to aPath’s stringByAppendingPathComponent:aName
    
anArray’s addObject:aFullPath
  end repeat
  
  
set thePred to NSPredicate’s predicateWithFormat:"pathExtension == [c]%@" argumentArray:{aExt}
  
set bArray to anArray’s filteredArrayUsingPredicate:thePred
  
  
return bArray as list
end retFullPathWithinAFolderWithRecursiveFilterByExt

–Bundle IDからアプリケーションのPathを返す
on retAppAbusolutePathFromBundleID(aBundleID)
  set appPath to current application’s NSWorkspace’s sharedWorkspace()’s absolutePathForAppBundleWithIdentifier:aBundleID
  
if appPath = missing value then return false
  
return appPath as string
end retAppAbusolutePathFromBundleID

–RAM上にスクリプトエディタと同じ部品を組み立て(非表示)、AppleScriptのソーステキストからObjectを生成し、Attributed Stringデータを返す
on compileASandReturnAttributedString(theSource as string)
  set targX to 1024 –View Width
  
set targY to 2048 –View Height
  
  
set osaCon to OSAScriptController’s alloc()’s init()
  
set osaView to OSAScriptView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, targX, targY))
  
  
set resView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, targX, targY))
  
resView’s setRichText:true
  
resView’s useAllLigatures:true
  
  
osaCon’s setScriptView:osaView
  
osaCon’s setLanguage:(OSALanguage’s languageForName:"AppleScript")
  
osaCon’s setResultView:resView
  
  
osaView’s setString:theSource
  
osaCon’s compileScript:(missing value) –Compile(構文確認)
  
  
set aRes to (osaView’s attributedString())
  
  
return aRes
end compileASandReturnAttributedString

–1D Listを文字列長でソート v2
on sort1DListByIndicatedStringLength(aList as list, aSortKey as string, sortOrder as boolean)
  set aArray to NSArray’s arrayWithArray:aList
  
set descLabel1 to NSString’s stringWithString:(aSortKey & ".length")
  
set descLabel2 to NSString’s stringWithString:aSortKey
  
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:descLabel1 ascending:sortOrder
  
set desc2 to NSSortDescriptor’s sortDescriptorWithKey:descLabel2 ascending:true selector:"localizedCaseInsensitiveCompare:"
  
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}
  
return bArray as list
end sort1DListByIndicatedStringLength

–リストを指定デリミタをはさんでテキスト化
on retStrFromArrayWithDelimiter(aList as list, aDelim as string)
  set anArray to NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retStrFromArrayWithDelimiter

–書式つきテキストを組み立てる
on makeRTFfromParameters(aStr as string, fontName as string, aFontSize as real, aKerning as real, aLineSpacing as real)
  set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize
  
set aKey1 to (NSFontAttributeName)
  
  
set aVal2 to NSColor’s blackColor()
  
set aKey2 to (NSForegroundColorAttributeName)
  
  
set aVal3 to aKerning
  
set akey3 to (NSKernAttributeName)
  
  
set aVal4 to 0
  
set akey4 to (NSUnderlineStyleAttributeName)
  
  
set aVal5 to 2 –all ligature ON
  
set akey5 to (NSLigatureAttributeName)
  
  
set aParagraphStyle to NSMutableParagraphStyle’s alloc()’s init()
  
aParagraphStyle’s setMinimumLineHeight:(aLineSpacing)
  
aParagraphStyle’s setMaximumLineHeight:(aLineSpacing)
  
set akey7 to (NSParagraphStyleAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey7}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aParagraphStyle}
  
set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
end makeRTFfromParameters

–指定のNSAttributedStringから書式情報をlist of recordで取得
on getAttributeRunsFromAttrString(theStyledText)
  script aSpd
    property styleList : {}
  end script
  
  
set (styleList of aSpd) to {} —for output
  
  
set thePureString to theStyledText’s |string|() –pure string from theStyledText
  
  
set theLength to theStyledText’s |length|()
  
set startIndex to 0
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) inRange:{startIndex, theLength – startIndex}
    
    
set aText to (thePureString’s substringWithRange:theRange) as string
    
    
set aColor to (theAtts’s valueForKeyPath:"NSColor")
    
if aColor is not equal to missing value then
      set aSpace to aColor’s colorSpace()
      
      
set aRed to (aColor’s redComponent()) * 255
      
set aGreen to (aColor’s greenComponent()) * 255
      
set aBlue to (aColor’s blueComponent()) * 255
      
      
set colList to {aRed as integer, aGreen as integer, aBlue as integer}
      
set colStrForFind to (aRed as integer as string) & " " & (aGreen as integer as string) & " " & (aBlue as integer as string)
    else
      set colList to {0, 0, 0}
      
set colStrForFind to "0 0 0"
    end if
    
    
set aFont to (theAtts’s valueForKeyPath:"NSFont")
    
if aFont is not equal to missing value then
      set aDFontName to aFont’s displayName()
      
set aDFontSize to aFont’s pointSize()
    end if
    
    
set the end of (styleList of aSpd) to {stringVal:aText, colorStr:colStrForFind, colorVal:colList, fontName:aDFontName as string, fontSize:aDFontSize}
    
set startIndex to current application’s NSMaxRange(theRange)
  end repeat
  
  
return (styleList of aSpd)
end getAttributeRunsFromAttrString

–1D Listをアイテムの出現頻度順でソートして返す
on countItemsByItsAppearance(aList as list)
  set aSet to NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"})
  end repeat
  
  
set theDesc to NSSortDescriptor’s sortDescriptorWithKey:"numberOfTimes" ascending:false
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

★Click Here to Open This Script 

Posted in file OSA recursive call Text | Tagged 10.11savvy 10.12savvy 10.13savvy NSArray NSAttributedString NSBundle NSColor NSCountedSet NSData NSDictionary NSFileManager NSFont NSMutableArray NSMutableAttributedString NSMutableDictionary NSMutableParagraphStyle NSPredicate NSSortDescriptor NSString NSTextView OSALanguage OSALanguageInstance OSAScript OSAScriptController OSAScriptView Script Editor Xcode | Leave a comment

AppleScriptの構文色分けカラーフォーマットをplistから読み込む

Posted on 3月 7, 2018 by Takaaki Naganoya

AppleScriptの構文色分けフォーマットをplistから読み込むAppleScriptです。

ただし、本Scriptで取得した色情報はスクリプトエディタ上で設定した内容と若干RGB値が異なるため、色情報をもとに構文要素を判定するような処理に本Scriptをそのまま用いることは推奨しません。

AppleScript名:AppleScriptの構文色分けカラーフォーマットをplistから読み込む
— Created 2013-11-11 by Shane Stanley
— Changed 2014-12-14 by Takaaki Naganoya
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set cList to getAppleScriptSourceColors() of me
–> {​​​​​{​​​​​​​redValue:37265, ​​​​​​​greenValue:10280, ​​​​​​​blueValue:37008, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:15672, ​​​​​​​greenValue:3071, ​​​​​​​blueValue:15832, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:3598, ​​​​​​​greenValue:15934, ​​​​​​​blueValue:64507, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:30840, ​​​​​​​greenValue:13364, ​​​​​​​blueValue:52171, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:64764, ​​​​​​​greenValue:10794, ​​​​​​​blueValue:7196, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:0, ​​​​​​​greenValue:0, ​​​​​​​blueValue:0, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:37265, ​​​​​​​greenValue:21074, ​​​​​​​blueValue:4369, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:0, ​​​​​​​greenValue:0, ​​​​​​​blueValue:0, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:10023, ​​​​​​​greenValue:51657, ​​​​​​​blueValue:51657, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:3855, ​​​​​​​greenValue:15934, ​​​​​​​blueValue:64507, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:7967, ​​​​​​​greenValue:46774, ​​​​​​​blueValue:64764, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:33153, ​​​​​​​greenValue:14906, ​​​​​​​blueValue:55769, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:23901, ​​​​​​​greenValue:13878, ​​​​​​​blueValue:37522, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:47484, ​​​​​​​greenValue:3164, ​​​​​​​blueValue:32926, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:6491, ​​​​​​​greenValue:47213, ​​​​​​​blueValue:32320, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:40001, ​​​​​​​greenValue:37149, ​​​​​​​blueValue:1331, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:20379, ​​​​​​​greenValue:0, ​​​​​​​blueValue:35059, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}, ​​​​​{​​​​​​​redValue:4539, ​​​​​​​greenValue:35536, ​​​​​​​blueValue:35798, ​​​​​​​fontName:"Osaka", ​​​​​​​fontSize:13.0​​​​​}​​​}

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceColors()
  
  
— get the info as a dictionary
  
set thePath to current application’s NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set colList to {}
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
log anEntry
    
    
set colorData to NSColor of anEntry
    
set theColor to (current application’s NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 65535) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (current application’s NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set aColRec to {redValue:rVal, greenValue:gVal, blueValue:bVal, fontName:aFontName, fontSize:aFontSize}
    
    
set the end of colList to aColRec
  end repeat
  
  
return colList
end getAppleScriptSourceColors

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aRed to round ((aCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((aCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((aCol’s blueComponent()) * aMAX) rounding as taught in school
  
  
if aRed > aMAX then set aRed to aMAX
  
if aGreen > aMAX then set aGreen to aMAX
  
if aBlue > aMAX then set aBlue to aMAX
  
  
return {aRed, aGreen, aBlue}
end retColListFromNSColor

★Click Here to Open This Script 

Posted in Color OSA System | Tagged 10.11savvy 10.12savvy 10.13savvy Script Editor | 3 Comments

指定パスのAppleScript書類がコンパイル済みかどうかチェック

Posted on 3月 7, 2018 by Takaaki Naganoya
AppleScript名:指定パスのAppleScript書類がコンパイル済みかどうかチェック
— Created 2014-12-16 by Takaaki Naganoya
— 2014 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "OSAKit"

property |NSURL| : a reference to current application’s |NSURL|
property OSAScript : a reference to current application’s OSAScript

–指定AppleScriptがコンパイルずみ(中間コードへの翻訳の意)かどうかをしらべる
set a to (choose file of type {"com.apple.applescript.script-bundle", "com.apple.applescript.script", "com.apple.applescript.text"})
set asRes to chkAScompiled(a) as list of string or string
–> true or false

–指定のAppleScriptファイルがコンパイル(構文確認+中間言語化)ずみかどうかを取得する
on chkAScompiled(anAlias as {alias, string})
  set aURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set asO to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
try
    set compF to asO’s isCompiled() as boolean
    
return compF
  on error
    return false
  end try
end chkAScompiled

★Click Here to Open This Script 

Posted in Color OSA System | Tagged 10.11savvy 10.12savvy 10.13savvy Script Editor | Leave a comment

指定パスのAppleScript書類のソース取得&コンパイルして結果をスタイル付きテキストで取得する v2

Posted on 3月 6, 2018 by Takaaki Naganoya

指定パスのAppleScript書類のソースを取得してコンパイル(構文確認)して実行し、結果を書式付きテキストとして取得してデスクトップにRTF書類として書き出すAppleScriptです。


▲テストに使用したテストスクリプト


▲実行結果。デスクトップ上にAppleScriptの構文色分けを反映させたRTFが書き出される

「AppleScriptの実行結果を書式付きテキストとして取得する」ことが目的です。本来であれば、スクリプトエディタ上でControl-Command-Rで「フロントエンドで実行」する必要があった(v1)のですが、Script Debugger上でも動くように少し書き換えました。

AppleScript名:指定パスのAppleScript書類のソース取得&コンパイルして結果をスタイル付きテキストで取得する v2
— Created 2016-01-08 by Takaaki Naganoya
— Modified 2018-03-05 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "OSAKit"
use framework "AppKit"
use framework "Quartz"

property NSFont : a reference to current application’s NSFont
property NSUUID : a reference to current application’s NSUUID
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property NSDictionary : a reference to current application’s NSDictionary
property NSMutableArray : a reference to current application’s NSMutableArray
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property NSDocumentTypeDocumentAttribute : a reference to current application’s NSDocumentTypeDocumentAttribute

property theResult : "" –result

set aScriptPath to POSIX path of (choose file with prompt "Choose AppleScript to convert to RTF" of type {"com.apple.applescript.script-bundle", "com.apple.applescript.script"})

— make sure the script is executed on the main thread
my performSelectorOnMainThread:"execASandReturnRTF:" withObject:aScriptPath waitUntilDone:true

–結果のRTFをデスクトップ上に書き出す。ファイル名はUUID.rtf
set targFol to current application’s NSHomeDirectory()’s stringByAppendingPathComponent:"Desktop"
set aRes to my saveStyledTextAsRTF(targFol, my theResult)

on execASandReturnRTF:anObject
  
  
set targX to 500 –View Width
  
set targY to 200 –View Height
  
set timeOutSecs to 180 –AppleScript execution timed out (Seconds)
  
  
–Select & Read AppleScript Source (Only Editable AppleScripts are available)
  
  
set srcStr to getASsourceFor(anObject) of me
  
log srcStr
  
if srcStr = missing value or srcStr = "" then
    –Error
    
display dialog "Error in reading script source…." buttons {"OK"} default button 1 with icon 1
    
return
  end if
  
  
–Make AppleScript Controller & Script Editor View
  
set osaCon to current application’s OSAScriptController’s alloc()’s init()
  
set osaView to current application’s OSAScriptView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, targX, targY))
  
  
–Make Result View
  
set resView to current application’s NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, targX, targY))
  
resView’s setRichText:true
  
resView’s useAllLigatures:true
  
  
–Connect OSAScriptController to Editor View & Result View
  
osaCon’s setScriptView:osaView
  
osaCon’s setResultView:resView
  
  
–Set AppleScript Source to Editor View & Execute it
  
osaView’s setString:srcStr
  
osaCon’s runScript:(missing value)
  
  
–Get AppleScript’s Result as string
  
set my theResult to (resView’s attributedString())
  
end execASandReturnRTF:

–make Window for Input
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
  set aScreen to current application’s NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to current application’s NSTitledWindowMask –NSBorderlessWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
— Window
  
set aWin to current application’s NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
–aWin’s setBackgroundColor:(current application’s NSColor’s whiteColor())
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(current application’s NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setAlphaValue:alphaV –append
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
aWin’s makeKeyAndOrderFront:(me)
  
  
— Set Custom View
  
aWin’s setContentView:aView
  
  
return aWin
  
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
— Original Created 2014-02-23 Shane Stanley
on getASsourceFor(aPOSIX as string)
  set aURL to current application’s |NSURL|’s fileURLWithPath:(aPOSIX)
  
set theScript to current application’s OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
return theScript’s source() as text
end getASsourceFor

–指定のAliasからファイル名を取得する
on getFileNameFromAlias(anAlias)
  set aPath to POSIX path of anAlias
  
set pathString to current application’s NSString’s stringWithString:aPath
  
set newPath to pathString’s lastPathComponent()
  
return newPath as string
end getFileNameFromAlias

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(targFol, aStyledString)
  set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to NSDictionary’s dictionaryWithObject:"NSRTFTextDocumentType" forKey:(NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
set theName to (NSUUID’s UUID()’s UUIDString())
  
set thePath to NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:"rtf"
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

★Click Here to Open This Script 

Posted in Color OSA RTF System | Tagged 10.11savvy 10.12savvy 10.13savvy Script Editor | Leave a comment

指定パスのAppleScriptを実行して結果をテキストで取得する(Main Thread実行を強制)

Posted on 3月 6, 2018 by Takaaki Naganoya

指定パスのAppleScript書類を実行して、結果をテキストとして取得するAppleScriptです。

本来、OSAScriptView上でのOSA言語プログラムの実行はメインスレッドでの実行が求められます。スクリプトエディタ上でControl-Command-Rで実行する「フロントエンドで実行」する操作です。

ただ、そのメインスレッドでの実行を強制指定できる実行環境(スクリプトエディタ、ASObjC Explorer 4)と、できない実行環境(アプレット、Script Menu、osascript、Script Debugger)があるので、AppleScriptのプログラム側から明示的にメインスレッドで他のAppleScriptを実行できないか模索していました。

Shane Stanleyからこの「performSelectorOnMainThread:」による強制的なメインスレッド実行の方法が提示されてはいたものの、使用できるScriptとできないScriptがあり、万能でないことも事実です(WindowつくってMapViewを乗せて地図表示するとか。AppKit呼び出してGUIをその場で生成するようなScriptはほぼダメ)。

とりあえず、このぐらいの(GUIを動的に生成してクリックを拾ってきたりしない)ものであれば使えそうだったので、ためしてみた次第です。

とくに、「Cocoaの機能を試してみる」という目的がなければ「run script」ほか数行で足りる内容です。あしからず。

AppleScript名:指定パスのAppleScriptを実行して結果をテキストで取得する(Main Thread実行を強制)
— Created 2016-01-08 by Takaaki Naganoya
— Created 2018-02-28 by Takaaki Naganoya
— 2016-2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "OSAKit"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSThread : a reference to current application’s NSThread
property OSAScript : a reference to current application’s OSAScript
property NSTextView : a reference to current application’s NSTextView
property OSAScriptView : a reference to current application’s OSAScriptView
property OSAScriptController : a reference to current application’s OSAScriptController

property theResult : "" –result

set my theResult to ""

–Select & Read AppleScript Source (Only Editable AppleScripts are available)
set aScriptPath to POSIX path of (choose file with prompt "Choose AppleScript to Execute" of type {"com.apple.applescript.script-bundle", "com.apple.applescript.script"})

— make sure the script is executed on the main thread
my performSelectorOnMainThread:"execASandReturnString:" withObject:aScriptPath waitUntilDone:true
return my theResult
–>  "{button returned:\"OK\"}"

on execASandReturnString:anObject
  
  
set targX to 500 –View Width
  
set targY to 200 –View Height
  
  
set srcStr to getASsourceFor(anObject) of me
  
if srcStr = missing value or srcStr = "" then
    –Error
    
display dialog "Error in reading script source…." buttons {"OK"} default button 1 with icon 1
    
return
  end if
  
  
–Make AppleScript Controller & Script Editor View
  
set osaCon to OSAScriptController’s alloc()’s init()
  
set osaView to OSAScriptView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, targX, targY))
  
  
–Make Result View
  
set resView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, targX, targY))
  
resView’s setRichText:true
  
resView’s useAllLigatures:true
  
  
–Connect OSAScriptController to Editor View & Result View
  
osaCon’s setScriptView:osaView
  
osaCon’s setResultView:resView
  
  
–Set AppleScript Source to Editor View & Execute it
  
osaView’s setString:srcStr
  
osaCon’s runScript:(missing value)
  
  
–Get AppleScript’s Result as string
  
set aRes to resView’s |string|() as list of string or string –as anything
  
  
set my theResult to aRes –Return the result as string
  
end execASandReturnString:

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
on getASsourceFor(anAlias as string)
  set aURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
return theScript’s source() as text
end getASsourceFor

★Click Here to Open This Script 

Posted in Color OSA System | Tagged 10.11savvy 10.12savvy 10.13savvy Script Editor | Leave a comment

nameを指定してOSA言語のインスタンスを生成する

Posted on 3月 6, 2018 by Takaaki Naganoya

name(名称)を指定してOSA言語のインスタンスを生成するテストを行うAppleScriptです。

このあたりの話は、スクリプトエディタ上では直接取得できますし、コマンドラインからだとosalangコマンドを実行すれば名称一覧を取得できます。Cocoa経由でどの程度の情報が取得できるのか、ちょっと試してながらく放置したままになっていました。

再度、OSAKit系の情報を探してみても……見当たらない(ーー;

以前にAppleEvent Managerのドキュメントをまるごとオフラインにしていた前科があるので、担当に「(オフラインになっていて)見えないんだけど?」と確認したところ………

 「何が見えないんだ? 最初からそんなもんないぞ。これまでにドキュメントを作ったこともない」

と言われる始末。余計悪いわ(ーー;;;

というわけで、Web上にドキュメントが掲載されていないOSAKit系の情報については、Xcode上から、以下のように操作してヘッダーファイルの内容を確認することが必要なようです。

AppleScript名:nameを指定してOSA言語のインスタンスを生成する
— Created 2018-03-05 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "OSAKit"

property OSALanguage : a reference to current application’s OSALanguage
property OSALanguageInstance : a reference to current application’s OSALanguageInstance

set anOSALanguageInstance to OSALanguageInstance’s languageInstanceWithLanguage:(OSALanguage’s defaultLanguage())
set aLanguage to anOSALanguageInstance’s |language|()’s |name|() as string
–> "AppleScript"

set bLanguage to OSALanguage’s languageForName:"AppleScript"
set bName to bLanguage’s |name|() as string
–> "AppleScript"

set cLanguage to OSALanguage’s languageForName:"JavaScript"
set cName to cLanguage’s |name|() as string
–> "JavaScript"

set langArray to (OSALanguage’s availableLanguages()’s valueForKeyPath:"name") as list
–> {"AppleScript", "JavaScript"}

★Click Here to Open This Script 

Posted in Color OSA System | Tagged 10.11savvy 10.12savvy 10.13savvy Script Editor | Leave a comment

Script Editorをコントロールして各構文要素の色情報を取得する v5

Posted on 3月 5, 2018 by Takaaki Naganoya

Script Editorをコントロールして、AppleScriptの各構文要素の色情報を取得するAppleScriptです。

AppleScriptの構文要素の色分けを取得するのに、当初はplistファイルから読み込んでいたのですが、途中から(Mac OS X 10.5あたり?)plistファイルのフォーマットがテキスト形式からバイナリ形式に変更になり、AppleScriptから読み込んでも判定できない内容になりました(Cocoaの機能を使うと読み取れるのですが)。

そこで、「プログラム的には意味はないが、対象の構文要素が入っているテキスト」でAppleScriptを新規ドキュメントを作成してコンパイル(構文確認)を実行。新規ドキュメントからリッチテキストとして書式情報を取得し、想定した文字の位置から指定構文要素に対応する色情報を取得します。

plistの保存形式が途中で変更されたのとは別に、書式つきテキスト(attribute runs)の挙動もOSバージョンによって微妙に変わってきました。

同じデータを与えても、書式の区切りが微妙に変わって、書式(色)情報を固定の箇所から読み取っていてはそのようなOSバージョン変更に伴う挙動の微妙な変更に対応し切れませんでした。そのため、文字列をサーチして毎回動的にデータ位置を検出するように書き換えた経緯があります。

本ルーチンは、変数名のリネーム用に作成したので構文要素確認用のダミーテキストは最低限のものだけを含んでいますが、その気になればすべての構文要素の色情報を取得可能です。

これとは別に、Cocoaの機能を用いてplistから構文書式情報を取得するAppleScriptも存在するものの、計算して微妙に色情報が合わないので、9年前に作成した本ルーチンを使い続けています。

AppleScript名:Script Editorをコントロールして各構文要素の色情報を取得する v5
— Created 2009-06-01 by Takaaki Naganoya
— 2009-2018 Piyomaru Software

set scList to getRexicalColorOfScriptEditor() of me
–> {{32053, 4213, 32213}, {15672, 3071, 15831}, {2841, 6963, 64125}, {8259, 42547, 64473}, {0, 0, 0}, {32202, 16452, 3889}}
–色書式データ。先頭から順番に、、、
–新規テキスト, 演算子など, スクリプティング予約語, コマンド名, 値(数値、データ), 変数およびサブルーチン名

–スクリプトエディタの各構文要素の指定色を返す
–v5の変更点:Leopard以降のStyle runsの挙動変化(スペースを分離する/しない)に対応し、動的にサンプル文を走査するようにした
–v4の変更点:構文要素検出時のテンポラリウィンドウ作成時にScript Editorを隠す
–v3の変更点:重複時のエラー検出を追加
on getRexicalColorOfScriptEditor()
  set aRes to setVisibleOfSpecifiedProcess("Script Editor", false) of me
  
  
set rexList to {"+", "set", "application", "Comment", "1", "a"} –文中から検索するテキスト要素
  
set colList to {} –色情報を入れるリスト
  
  
  
tell application "Script Editor"
    
    
set aDoc to make new document
    
tell front document
      set aName to name
      
–end tell
      
      
–tell document aName
      
–未コンパイル時のテキストを取得
      
set contents to "aaaaa"
      
set rexItem1 to (color of attribute runs)
      
set rexItem1 to contents of (item 1 of rexItem1)
      
      
set colList to {rexItem1}
      
      
      
–各種構文要素を含む文字を入れる
      
set contents to "1 + 1
set a to \"abc\"
tell application \"Finder\"
end tell
–Comment
"

      –追加する場合には、テキストを後ろに追加すること
      
      
try
        compile
      on error
        close without saving
        
return false
      end try
      
      
set rex1 to attribute runs
      
set rex2 to color of attribute runs
      
      
repeat with i in rexList
        set j to contents of i
        
set rC to 1
        
repeat with ii in rex1
          set jj to contents of ii
          
set jj to replaceText(jj, " ", "") of me –スペースを削除する
          
if j = jj then
            set the end of colList to contents of item rC of rex2
            
exit repeat –抜けていた
          end if
          
set rC to rC + 1
        end repeat
      end repeat
      
      
close without saving
    end tell
    
  end tell
  
  
–Script Editorの再表示
  
set aRes to setVisibleOfSpecifiedProcess("Script Editor", true) of me
  
  
–要素の重複検出
  
set aRes to detectDuplicationSimple(colList) of me
  
if aRes = false then
    return false
  else
    return colList
  end if
  
end getRexicalColorOfScriptEditor

–リスト中の重複検出
on detectDuplicationSimple(cList)
  copy cList to ccList
  
  
set j to length of ccList
  
  
repeat with i from 2 to j
    set first_item to item 1 of ccList
    
set ccList to rest of ccList
    
if first_item is in ccList then
      return false
    end if
  end repeat
  
  
return true
end detectDuplicationSimple

–指定プロセスの可視/不可視切り替え
on setVisibleOfSpecifiedProcess(aProc, aBoolean)
  tell application "System Events"
    if exists process aProc then
      set visible of process aProc to aBoolean
      
set resF to true
    else
      set resF to false
    end if
  end tell
  
return resF
end setVisibleOfSpecifiedProcess

–任意のデータから特定の文字列を置換
on replaceText(origData, origText, repText)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {origText}
  
set origData to text items of origData
  
set AppleScript’s text item delimiters to {repText}
  
set origData to origData as text
  
set AppleScript’s text item delimiters to curDelim
  
return origData
end replaceText

★Click Here to Open This Script 

Posted in Color OSA System | Tagged 10.11savvy 10.12savvy 10.13savvy Script Editor | 1 Comment

asHTMLexportLib v2

Posted on 2月 8, 2018 by Takaaki Naganoya

指定のAppleScript書類をスクリプトエディタでオープンし、書式情報を読み取ってURLリンク付きのHTML(テキスト)を生成するAppleScriptです。AppleScript Librariesとして他のScriptから呼び出して利用しています。

オリジナルは2006年ごろに作成したもので、「秘伝のタレ」よろしくその時々のOSの変更を反映させて使い続けています。

AppleScriptの書式(とくに色情報)をHTML書き出し時にどのように反映させるかについては、いろいろと「流派」があり、

 ・スクリプトエディタ上の色情報を読み取ってそのままカラータグで展開する派
 ・CSSなどで構文要素ごとにスタイルを指定する派

で、本Scriptは前者の方式で書かれた最古のScriptの末裔です。書き出しHTMLが長くなるというデメリットはあるものの、構造の単純さが幸いしてわずかな修正でメンテナンスを継続できています。

当初、AppleScriptからスクリプトエディタをコントロールすると不具合が多く、他のAppleScript開発環境(Script Debugger)からの実行を余儀なくされていました。macOS 10.6あたりでずいぶん安定して利用できるようになってきた記憶があります(10.3とか10.4はいま思い出しても辛かった)。

HTMLに埋め込むURLスキーム「applescript:」からは、AppleScriptの新規作成、作成中のAppleScript書類のカーソル位置へのペースト、書類末尾へのペーストなどの動作を指定できますが、結局Blogに10年前からつけているURLリンクもそれほど認識されておらず(なぜ??)、新規作成のリンクのみ付加するように変更しました。

また、「applescript:」のURLリンクでは生成するAppleScript書類のファイル名をあらかじめ指定できるようになっているものの、古いバージョンのmacOS(Mac OS X)ではこの名称指定が仇となってURLリンクが認識されないという問題が発生するため、名称も指定していません。

一応、書き出し対象ファイルがAppleScriptかJavaScriptかを判定して、書き出し時のカラーリングを変更するようになっています。OSAScriptフレームワーク経由で書類から直接OSA言語の種別は取得できるものの、スクリプトエディタ自体から情報を取得しても手間はたいして変わらないので現状のようになっています。

AppleScript名:asHTMLexportLib
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property quotChar : string id 34

property headerCol : "0000CC" –"0000CC" –ヘッダー部分(濃い色)
property bodyBackCol : "EEFFFF" –"EEFFFF" –Script本文下地(薄い色)
property footerCol : "66FFFF" –"66FFFF" –スクリプトリンク部分
property repMark : "_replacepoint_"

on run
  set aPath to choose file of type {"com.apple.applescript.script", "com.apple.applescript.script-bundle"}
  
set aRes to retScriptHTML(aPath) of me
end run

on retScriptHTML(aPath) –parameter is alias
  script spd
    property TIDsList : {}
    
property dataOut : {}
    
property textList : {}
    
property colorList : {}
  end script
  
  
set pName to "com.apple.ScriptEditor2"
  
  
tell application id pName
    set asDoc to open aPath
    
    
tell asDoc –front document
      set aInfo to properties
      
set curLang to name of language of aInfo –現在のOSA言語の名称を取得する
    end tell
    
    
–OSA Language名称をもとに色セットを変更する
    
changeColor(curLang) of me
    
    
set c to name of asDoc –front document
    
    
set aF to aPath as string –retMacOSpathList(aPath) of me
    
    
set contText to getContentsOfFile(asDoc) of me –front document
    
set encText to makeEncodedScript(contText) of me
    
    
set newLinkText to "applescript://com.apple.scripteditor?action=new&script=" & encText
    
–set insLinkText to "applescript://com.apple.scripteditor?action=insert&script=" & encText
    
–set apndLinkText to "applescript://com.apple.scripteditor?action=append&script=" & encText
    
    
set comText to description of asDoc –front document
    
    
set (textList of spd) to getAttributeRunOfFile(asDoc) of me —every attribute run of asDoc –front document
    
set (colorList of spd) to getColorOfAttributeRunOfFile(asDoc) of me —color of every attribute run of asDoc –front document
    
  end tell
  
  
set tabChar to string id 9
  
  
set (TIDsList of spd) to {{"\\", "\"}, {"’", "’"}, {"&", "&amp;"}, {">", "&gt;"}, {"<", "&lt;"}, {"  ", "  "}, {string id 13, "<br>"}, {string id 10, "<br>"}, {"\"", "&quot;"}}
  
  
  
set (dataOut of spd) to {}
  
  
set iCounter to 1
  
repeat with i in (textList of spd)
    set j to contents of i
    
    
set curDelim to AppleScript’s text item delimiters
    
repeat with eachItem in (TIDsList of spd)
      set AppleScript’s text item delimiters to contents of item 1 of eachItem
      
set j to every text item of j
      
set AppleScript’s text item delimiters to contents of item 2 of eachItem
      
set j to j as string
    end repeat
    
set AppleScript’s text item delimiters to curDelim
    
    
set cText to RBG2HTML(item iCounter of (colorList of spd)) of me
    
    
set the end of (dataOut of spd) to "<font color=" & cText & ">" & j & "</font>"
    
set iCounter to iCounter + 1
  end repeat
  
  
  
set htmlHeader to "<table width=" & quotChar & "100%" & quotChar & " border=" & quotChar & "0" & quotChar & "cellspacing=" & quotChar & "2" & quotChar & " cellpadding=" & quotChar & "2" & quotChar & ">
<tr>
<td bgcolor=\"#" & headerCol & "\"><font color=" & quotChar & "#FFFFFF" & quotChar & ">" & curLang & "名:" & c
  
  
if comText is not equal to "" then
    set comText to "<br><font size=" & quotChar & "2" & quotChar & ">【Comment】 " & comText & "</font><br>"
  end if
  
  
set htmlHeader2 to "</font></td>
</tr>
<tr>
<td bgcolor=\"#" & bodyBackCol & "\"><font size=\"3\">"
  
  
set htmlFooter1 to "</font></td>
</tr>
<tr>
<td bgcolor=\"#" & footerCol & "\"><p><font size=\"2\"><a href=\"" & newLinkText & "\">★Click Here to Open This Script</a> </font></p>
</td>
</tr>
</table>
"

  
  
set dataText to htmlHeader & comText & htmlHeader2 & ((dataOut of spd) as text) & htmlFooter1
  
set dataText to dataText as Unicode text
  
  
tell application id pName
    close asDoc without saving
    
–close front document without saving
  end tell
  
  
return dataText
end retScriptHTML

on makeEncodedScript(contText)
  set aList to every paragraph of contText
  
set aClass to class of aList
  
if aClass = list then
    set aLen to length of aList
  else
    set aLen to 1
  end if
  
  
set aaList to {}
  
  
set delim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to repMark
  
set bList to aList as text
  
set AppleScript’s text item delimiters to delim
  
  
set aaList to (retURLencodedStrings(bList) of me) as text
  
  
set search_string to retURLencodedStrings(repMark) of me –"%5Freplacepoint%5F" as text
  
set replacement_string to "%0D" as text
  
set bList to replace_chars(aaList, search_string, replacement_string) of me
  
  
return bList
end makeEncodedScript

–RGB値からHTMLの色指定に変換
on RBG2HTML(RGB_values)
  — NOTE: this sub-routine expects the RBG values to be from 0 to 65536
  
set the hex_list to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
  
set the the hex_value to ""
  
repeat with i from 1 to the count of the RGB_values
    set this_value to (item i of the RGB_values) div 256
    
if this_value is 256 then set this_value to 255
    
set x to item ((this_value div 16) + 1) of the hex_list
    
set y to item (((this_value / 16 mod 1) * 16) + 1) of the hex_list
    
set the hex_value to (the hex_value & x & y) as string
  end repeat
  
return ("#" & the hex_value) as string
end RBG2HTML

on replace_chars(this_text, search_string, replacement_string)
  set AppleScript’s text item delimiters to the search_string
  
set the item_list to every text item of this_text
  
set AppleScript’s text item delimiters to the replacement_string
  
set this_text to the item_list as string
  
set AppleScript’s text item delimiters to ""
  
return this_text
end replace_chars

on retURLencodedStrings(aText)
  set aStr to current application’s NSString’s stringWithString:aText
  
set encodedStr to aStr’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s alphanumericCharacterSet())
  
return encodedStr as text
end retURLencodedStrings

on changeColor(aLang)
  if aLang = "AppleScript" then
    set headerCol to "0000CC" –"0000CC" –ヘッダー部分(濃い色)
    
set bodyBackCol to "EEFFFF" –"EEFFFF" –Script本文下地(薄い色)
    
set footerCol to "66FFFF" –"66FFFF" –スクリプトリンク部分
  else if aLang = "JavaScript" then
    set headerCol to "804000" –"0000CC" –ヘッダー部分(濃い色)
    
set bodyBackCol to "E2D3D3" –"EEFFFF" –Script本文下地(薄い色)
    
set footerCol to "E7AC53" –"66FFFF" –スクリプトリンク部分
  end if
end changeColor

on getContentsOfFile(asDoc)
  tell application id "com.apple.ScriptEditor2"
    set aCon to (properties of asDoc)
  end tell
  
return contents of aCon
end getContentsOfFile

on getAttributeRunOfFile(asDoc)
  tell application id "com.apple.ScriptEditor2"
    set aCon to (every attribute run of asDoc)
  end tell
  
return aCon
end getAttributeRunOfFile

on getColorOfAttributeRunOfFile(asDoc)
  tell application id "com.apple.ScriptEditor2"
    set aCon to color of (every attribute run of asDoc)
  end tell
  
return aCon
end getColorOfAttributeRunOfFile

★Click Here to Open This Script 

Posted in Text | Tagged 10.11savvy 10.12savvy 10.13savvy Script Editor | Leave a comment

電子書籍(PDF)をオンラインストアで販売中!

Popular Posts

  • Pages書類の1ページ目の表の背景色を置換
  • 数値演算ライブラリ「calcLibAS」v1.3(28倍速)
  • choose style lib
  • 数値演算ライブラリ「calcLibAS」
  • AppleScript上でJavaScriptを実行する
  • CotEditorのScript集、PowerPack & Basic Packをv2.0にアップデート
  • macOS 10.14 AppleScriptリリースノート
  • Dynamic Menu Clicker
  • JPEG画像の破損チェック
  • Numbersで選択範囲のセルのデータを取得して重複データを抽出
  • Keynote書類のテキスト色を置換
  • PDFフォームに入力して別名保存
  • iCloud Driveフォルダへのパスを求める
  • macOS 10.15beta関連
  • 指定フォルダ内の指定拡張子のファイルのうち、指定キーワードで始まるものを
  • 画面上の指定座標にマウスカーソルを強制移動させてクリック
  • WiFiデバイスのパワーをオンに
  • PDFから指定ページ以降を削除
  • 表示中のYouTubeのムービーをローカルにダウンロード v2
  • 指定PDFの最初のページからアノテーションを取得する

Tags

10.11savvy (1121) 10.12savvy (1248) 10.13savvy (1241) 10.14savvy (296) 10.15savvy (72) CotEditor (42) Finder (36) ITLibrary (13) iTunes (24) Keynote (46) Mail (11) NSAlert (33) NSAlertSecondButtonReturn (13) NSArray (51) NSBezierPath (11) NSBitmapImageRep (15) NSButton (17) NSColor (39) NSCountedSet (16) NSDictionary (26) NSFileManager (20) NSFont (13) NSImage (31) NSJSONSerialization (11) NSMutableArray (48) NSMutableDictionary (19) NSPredicate (37) NSRunningApplication (31) NSScreen (22) NSScrollView (17) NSSortDescriptor (15) NSString (87) NSTextView (11) NSURL (58) NSUTF8StringEncoding (12) NSUUID (15) NSView (27) NSWindow (11) NSWorkspace (12) Numbers (33) OSALanguage (11) OSAScript (17) Safari (24) Script Editor (16) TextEdit (13)

カテゴリー

  • AirDrop
  • AirPlay
  • AppleScript Application on Xcode
  • Bluetooth
  • boolean
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • dialog
  • drive
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • font
  • geolocation
  • GUI
  • GUI Scripting
  • How To
  • Icon
  • Image
  • Input Method
  • Internet
  • JXA
  • Keychain
  • Language
  • list
  • Locale
  • Machine Learning
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • Noification
  • Notarization
  • Number
  • OCR
  • OSA
  • PDF
  • QR Code
  • Raw AppleEvent Code
  • Record
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • shell script
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Text
  • Text to Speech
  • timezone
  • Tools
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月





メタ情報

  • 登録
  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC