Menu

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

AppleScriptの穴

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

タグ: 13.0savvy

Skimがv1.7.8でopen locationコマンドを削除

Posted on 1月 14 by Takaaki Naganoya

オープンソースのPDFビューワー「Skim」がバージョン1.7.8において「open location」コマンドを削除しました。

open locationコマンドは標準装備されているものであり、Skim側で実装しなくても問題ないという結論に至ったのかもしれません。

なお、オープンできる(Skimが応答する)URLはhttps://のみであり、http://については応答しないのもv1.7.6から変わっていません。

ただ、これまでにSkimは何度も「トラブルを起こしたコマンドをいったん削除してあとあと再実装」という動きをしているので、再実装される可能性は否定できません。しらんけど。

Posted in URL | Tagged 13.0savvy 14.0savvy 15.0savvy Skim | Leave a comment

選択範囲の値を取得して、冒頭の値の新しい数値を指定すると以下自動加算

Posted on 1月 14 by Takaaki Naganoya

Numbers上で選択範囲のデータに対して一括で数値を加算するAppleScriptです。

Numbers上で台割(PDFに対して付加するTOC用データ)を管理しているところに、実際の電子書籍の記事が増えて、各記事のノンブル(ページ番号)を変更する必要があるわけですが……これに、当初は「+18で」みたいなScriptを運用していたのですが、暗算で差分を計算していたものの、この仕様だと使いにくかったのです。

そこで、新たなページ数を入力すると、AppleSript側で差分を計算して後の選択範囲に対して加算するようにしてみました。


▲初期状態


▲PDFを参照して新版の「おくづけ」は552ページになっていることを確認 ここで、本Scriptを実行


▲差分(増分)を暗算で計算して入力するのではなく、最初のページの変更後のページ数が何か、を入力。Script側で差分を自動計算


▲実行後の状態

巨大なScriptも役立ちますが、こういう「ちょっとした」サイズのScriptもまた役に立ちます。

AppleScript名:選択範囲の値を取得して、冒頭の値の新しい数値を指定すると以下自動加算.scpt
set sNum to text returned of (display dialog "Input New First Num" default answer "")
tell application "Numbers"
  tell front document
    tell active sheet
      tell table 1
        set mySelectedRanges to value of every cell of selection range
        
set cellList to cell of selection range
        
        
set addNum to sNum – (first item of mySelectedRanges)
        
        
        
set iCount to 0
        
set newList to {}
        
repeat with i in cellList
          set tmpVal to value of i
          
set the end of newList to tmpVal + addNum
        end repeat
        
        
repeat with i from 1 to (length of cellList)
          tell item i of cellList
            set value to item i of newList
          end tell
        end repeat
      end tell
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in Number | Tagged 13.0savvy 14.0savvy 15.0savvy Numbers | Leave a comment

スタイルつきテキストでスタイルつきテキストを検索 v1.1

Posted on 1月 13 by Takaaki Naganoya

スタイルつきテキストの中をスタイルつきテキストで検索するAppleScriptです。フォント、サイズ、色の属性を考慮して文字とこれらの属性値が合っている場合に合致しているものとみなします。

最初のバージョンはChatGPTに書かせたもので、実際に動かしてみたら激遅だったので、2パスで検索することで高速化してみました。オリジナルより100倍以上速くなっているはずです。

Step1: 検索対象文字列、検索文字列の両方をテキスト化して、テキストベースで出現情報を計算
Step2: 出現情報をもとにスタイルつきテキスト(NSAttributedString)の書式情報の照合を行い、合致するものを出力

という処理に変更しました。ChatGPTが出力してきたAppleScriptは、1文字ずつチェック範囲を変更しながら書式情報とテキスト情報の照合を行うという「脳筋処理」だったので、少なく見積もっても100倍。データ量が増えれば増えるほど高速化の度合いが上昇します。

AppleScript名:find Styled Text in Styled Text_v1.1.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2025/01/12
—
–  Copyright © 2025 Piyomaru Software, All Rights Reserved
—

use AppleScript
use framework "Foundation"
use scripting additions

property NSString : a reference to current application’s NSString
property NSLiteralSearch : a reference to current application’s NSLiteralSearch
property NSMutableArray : a reference to current application’s NSMutableArray

— サンプルデータ
set targetText to "これはサンプルテキストです。サンプルは重要です。サンプルだよー。サンプルサンプル"
set searchText to "サンプル"

— 属性付き文字列の作成
set targetAttributedString to current application’s NSMutableAttributedString’s alloc()’s initWithString:targetText
set searchAttributedString to current application’s NSMutableAttributedString’s alloc()’s initWithString:searchText

— 属性を設定 (例: フォントと色)
set targetFont to current application’s NSFont’s fontWithName:"HiraginoSans-W2" |size|:13
set targetColor to current application’s NSColor’s redColor()
set searchFont to current application’s NSFont’s fontWithName:"HiraginoSans-W2" |size|:13
set searchColor to current application’s NSColor’s redColor()

— 属性を追加
targetAttributedString’s addAttribute:(current application’s NSFontAttributeName) value:targetFont range:{0, targetAttributedString’s |length|()}
targetAttributedString’s addAttribute:(current application’s NSForegroundColorAttributeName) value:targetColor range:{0, targetAttributedString’s |length|()}
searchAttributedString’s addAttribute:(current application’s NSFontAttributeName) value:searchFont range:{0, searchAttributedString’s |length|()}
searchAttributedString’s addAttribute:(current application’s NSForegroundColorAttributeName) value:searchColor range:{0, searchAttributedString’s |length|()}

— 属性付き検索を実行
set matches to searchAttributedStringWithAttributes(targetAttributedString, searchAttributedString) of me
–> {{location:3, |length|:4}, {location:14, |length|:4}, {location:24, |length|:4}, {location:32, |length|:4}, {location:36, |length|:4}}

— NSAttributedStringの属性付き検索を行うハンドラー(複数一致対応)
on searchAttributedStringWithAttributes(targetAttributedString, searchAttributedString)
  set targText to targetAttributedString’s |string|() as string
  
  
set searchAttributes to searchAttributedString’s attributesAtIndex:0 effectiveRange:(missing value)
  
set searchString to searchAttributedString’s |string|() as string
  
  
–テキストベースで検索
  
set strRangeList to searchWordRanges(targText, searchString) of me
  
–あとは、検索箇所の文字書式をループで照合する
  
  
set matList to {} — 結果を格納するリスト
  
  
— ループで対象の文字列が含まれる位置の書式情報を検索
  
repeat with i in strRangeList
    set j to contents of i
    
set tmpLoc to location of j
    
set tmpLen to |length| of j
    
    
— 対象範囲の属性を取得
    
set targetAttributes to (targetAttributedString’s attributesAtIndex:(tmpLoc) effectiveRange:(current application’s NSMakeRange(tmpLoc, tmpLen)))
    
    
if (targetAttributes = searchAttributes) then
      set the end of matList to {location:(tmpLoc as integer), |length|:(tmpLen as integer)} — 属性が一致した場合
    end if
  end repeat
  
  
return matList — 一致したすべての範囲を返す
end searchAttributedStringWithAttributes

–プレーンテキストベースで検索文字列の出現情報を返す(複数対応)
on searchWordRanges(aTargText as string, aSearchStr as string)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:(NSLiteralSearch) range:aRange
    
set aLen to (detectedRange’s |length|) as number
    
    
if aLen = 0 then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to (detectedRange’s location) as number
    
set bNum to (detectedRange’s |length|) as number
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum – (aNum + bNum))
  end repeat
  
  
return hitArray
end searchWordRanges

★Click Here to Open This Script 

Posted in RTF search | Tagged 13.0savvy 14.0savvy 15.0savvy NSColor NSFont NSLiteralSearch NSMutableArray NSMutableAttributedString NSString | Leave a comment

スタイルつきテキストでスタイルつきテキストを検索

Posted on 1月 13 by Takaaki Naganoya

スタイルつきテキストの中をスタイルつきテキストで検索するAppleScriptです。フォント、サイズ、色の属性を考慮して文字とこれらの属性値が合っている場合に合致しているものとみなします。

たかだか3Kバイトごときの文字量のスタイルつきテキストから検索を行うのに、M2 Airで2・3秒ぐらいかかります。

属性値をDictionary in Arrayとして解釈して検索を行うよりも、大幅に処理に時間がかかるようです。

1文字ずつ開始位置をズラして文字&書式の再照合を行っているので、アホみたいに処理時間がかかります。Cocoaの機能を使って処理しているのに、Pagesに問い合わせるよりも時間がかかっている雰囲気です。

本ScriptはChatGPTに書かせたもので、おそらく処理に時間がかかって「無駄」になるものと見込んでいました。

スタイルつきテキストに対してスタイルつきテキストによる検索を行うのは、予想どおりものすごく負荷が大きくなるようで……本Scriptは残念ながら作り捨てになりそうです。

もう少し頭を使って、文字だけで出現位置チェックを行い、出現位置情報をもとに書式の照合を行うようにすれば、10倍ぐらい高速に処理できそうです。

AppleScript名:find Styled Text in Styled Text.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2025/01/12
—
–  Copyright © 2025 Piyomaru Software, All Rights Reserved
—

use AppleScript
use framework "Foundation"
use scripting additions

— 使用例
set targetText to "これはサンプルテキストです。サンプルは重要です。サンプルだよー。"
set searchText to "サンプル"

— 属性付き文字列の作成
set targetAttributedString to current application’s NSMutableAttributedString’s alloc()’s initWithString:targetText
set searchAttributedString to current application’s NSMutableAttributedString’s alloc()’s initWithString:searchText

— 属性を設定 (例: フォントと色)
set targetFont to current application’s NSFont’s fontWithName:"HiraginoSans-W2" |size|:13
set targetColor to current application’s NSColor’s redColor()
set searchFont to current application’s NSFont’s fontWithName:"HiraginoSans-W2" |size|:13
set searchColor to current application’s NSColor’s redColor()

— 属性を追加
targetAttributedString’s addAttribute:(current application’s NSFontAttributeName) value:targetFont range:{0, targetAttributedString’s |length|()}
targetAttributedString’s addAttribute:(current application’s NSForegroundColorAttributeName) value:targetColor range:{0, targetAttributedString’s |length|()}
searchAttributedString’s addAttribute:(current application’s NSFontAttributeName) value:searchFont range:{0, searchAttributedString’s |length|()}
searchAttributedString’s addAttribute:(current application’s NSForegroundColorAttributeName) value:searchColor range:{0, searchAttributedString’s |length|()}

— 属性付き検索を実行
set matches to searchAttributedStringWithAttributes(targetAttributedString, searchAttributedString) of me
–> {{location:3, |length|:4}, {location:14, |length|:4}, {location:24, |length|:4}}

— NSAttributedStringの属性付き検索を行うハンドラー(複数一致対応、変数名変更)
on searchAttributedStringWithAttributes(targetAttributedString, searchAttributedString)
  — 検索対象の全長を取得
  
set targetLength to targetAttributedString’s |length|()
  
set searchLength to searchAttributedString’s |length|()
  
  
— 検索する属性辞書を取得
  
set searchAttributes to searchAttributedString’s attributesAtIndex:0 effectiveRange:(missing value)
  
set searchString to searchAttributedString’s |string|() as string
  
  
— 結果を格納するリスト
  
set matches to {}
  
  
— ループで対象の文字列を検索
  
set currentIndex to 1
  
  
repeat while (currentIndex + searchLength ≤ targetLength)
    — 対象範囲の属性辞書を取得
    
set targetAttributes to targetAttributedString’s attributesAtIndex:currentIndex effectiveRange:(missing value)
    
    
— 対象範囲の文字列を取得
    
set targetRange to (current application’s NSMakeRange(currentIndex, searchLength))
    
set targetSubstring to (targetAttributedString’s attributedSubstringFromRange:(targetRange))’s |string|()
    
    
— 属性と文字列の一致を確認
    
if (targetSubstring as string = searchString) and (targetAttributes = searchAttributes) then
      set end of matches to {location:currentIndex, |length|:searchLength}
    end if
    
    
— 次の位置に進む
    
set currentIndex to currentIndex + 1
  end repeat
  
  
return matches — 一致したすべての範囲を返す
end searchAttributedStringWithAttributes

★Click Here to Open This Script 

Posted in RTF | Tagged 13.0savvy 14.0savvy 15.0savvy NSMutableAttributedString | Leave a comment

AS書類を書式で分解して再構成

Posted on 1月 12 by Takaaki Naganoya

AppleScriptの書類を読み込んでNSAttributedStringに変換し、書式情報にもとづいてNSDictionary in NSArrayに変換。この状態でデータ抽出などを行なっていたのですが、このデータをもとにNSAttributedStringに再構成するAppleScriptです。

本Scriptの通しの処理内容としては、読み込んだAppleScriptを書式情報をもとに分解して、再構成するという……大豆から豆腐を作って、豆腐を崩して豆を得る、みたいな内容です。

NSAttributedStringを再構成する部分の処理を書いていなかったので、必要に迫られて書いてみました。

AppleScript構文色分け設定情報をもとに処理するため、色分け設定で複数の構文要素で同じ色を指定している場合にはエラーを返します。単にNSAttributedStringを解釈して再構成する、といった処理であればAppleScript構文色分け設定へのアクセス自体は必要ないところですが、すでに不可分なレベルで組み込まれているため、現状ではそのままです。

いっそ、こうした処理をする前にplistをバックアップし、必要な情報を書き込んだplistを設定ファイルとして使用するといった処理を行った方がいいのかもしれません。これまでは、「そんな処理はとても行えない」と判断していましたが、よくよく考えればとくに苦労せずに実現できそうです。

AppleScript名:AS書類を書式で分解して再構成.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2025/01/12
—
–  Copyright © 2025 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSFont : a reference to current application’s NSFont
property NSColor : a reference to current application’s NSColor
property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property OSAScript : a reference to current application’s OSAScript
property NSDictionary : a reference to current application’s NSDictionary
property NSUnarchiver : a reference to current application’s NSUnarchiver
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
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 asCol : {}

set asCol to getAppleScriptSourceColors() of me –AppleScript構文色分け設定をplistから読み込む

set aFile to POSIX path of (choose file of type {"com.apple.applescript.script", "com.apple.applescript.script-bundle"})
set aURL to |NSURL|’s fileURLWithPath:(aFile)
set theScript to current application’s OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
set styledText to theScript’s richTextSource()

–Styled TextをDictionarry in Listに
set sRes to getAttributeRunsFromAttrStringRBO(styledText) of styleTextToDict

–Dictionarry in ListをStyled Textに再構成
set bRes to retAttributedStringFromAttrDict(sRes) of attrDictToAttrStr

script styleTextToDict
  use AppleScript
  
use framework "Foundation"
  
use framework "AppKit"
  
use scripting additions
  
property parent : AppleScript
  
  
–Styled Textを
  
on getAttributeRunsFromAttrStringRBO(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
    
set aCount to 0
    
    
repeat until (startIndex = theLength)
      set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) inRange:{startIndex, theLength – startIndex}
      
      
–String  
      
set aText to (thePureString’s substringWithRange:theRange) as string
      
set strLen to (length of aText)
      
      
–Color
      
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} –for comparison
        
set colStrForFind to (aRed as integer as string) & " " & (aGreen as integer as string) & " " & (aBlue as integer as string) –for filtering
      else
        set colList to {0, 0, 0}
        
set colStrForFind to "0 0 0"
      end if
      
      
–Font
      
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
      
      
–Range
      
set the end of (styleList of aSpd) to {stringVal:aText, atrIndex:aCount, colorStr:colStrForFind, colorVal:colList, fontName:aDFontName as string, fontSize:aDFontSize}
      
set startIndex to current application’s NSMaxRange(theRange)
      
      
set aCount to aCount + 1
    end repeat
    
    
return (styleList of aSpd)
    
  end getAttributeRunsFromAttrStringRBO
  
  
–NSColorからRGBの値を取り出す
  
on retColListFromNSColor(aCol, aMAX as integer)
    using terms from scripting additions
      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
    end using terms from
    
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
  
  
–aMaxValを最大値とする数値でNSColorを作成して返す
  
on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
    set aRedCocoa to (redValue / aMaxVal) as real
    
set aGreenCocoa to (greenValue / aMaxVal) as real
    
set aBlueCocoa to (blueValue / aMaxVal) as real
    
set aAlphaCocoa to (alphaValue / aMaxVal) as real
    
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
    
return aColor
  end makeNSColorFromRGBAval
  
end script

script attrDictToAttrStr
  use AppleScript
  
use framework "Foundation"
  
use framework "AppKit"
  
use scripting additions
  
property parent : AppleScript
  
  
–書式つきテキストを組み立てる(メイン側)
  
on retAttributedStringFromAttrDict(attrRes)
    script aSpd
      property styleList : {}
    end script
    
    
set (styleList of aSpd) to {} —for output
    
    
set allAttrStr to NSMutableAttributedString’s alloc()’s init()
    
    
repeat with i in attrRes
      set j to contents of i
      
set tmpAttrStr to makeRTFfromParameters(stringVal of j, fontName of j, fontSize of j, colorVal of j) of me
      
      (
allAttrStr’s appendAttributedString:tmpAttrStr)
    end repeat
    
    
return allAttrStr
  end retAttributedStringFromAttrDict
  
  
–書式つきテキストを組み立てる(パーツ組み立て用サブ側)
  
on makeRTFfromParameters(aStr as string, fontName as string, aFontSize as real, aColorList as list)
    –Font & Size
    
set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize
    
set aKey1 to (NSFontAttributeName)
    
    
–Color
    
copy aColorList to {rCol, gCol, bCOl}
    
set aVal2 to makeNSColorFromRGBAval(rCol, gCol, bCOl, 255, 255) of asCol
    
set aKey2 to (NSForegroundColorAttributeName)
    
    
set keyList to {aKey1, aKey2}
    
set valList to {aVal1, aVal2}
    
set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
    
    
–Text
    
set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
    
return attrStr
  end makeRTFfromParameters
  
  
  
–aMaxValを最大値とする数値でNSColorを作成して返す
  
on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
    set aRedCocoa to (redValue / aMaxVal) as real
    
set aGreenCocoa to (greenValue / aMaxVal) as real
    
set aBlueCocoa to (blueValue / aMaxVal) as real
    
set aAlphaCocoa to (alphaValue / aMaxVal) as real
    
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
    
return aColor
  end makeNSColorFromRGBAval
  
end script

–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

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  using terms from scripting additions
    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
  end using terms from
  
  
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 file Font OSA RTF | Tagged 13.0savvy 14.0savvy 15.0savvy NSAttributedString NSColor NSDictionary NSFont NSMutableAttributedString NSMutableDictionary NSString NSUnarchiver NSURL OSAScript | Leave a comment

OSAScriptViewのじっけん#2

Posted on 1月 9 by Takaaki Naganoya

OSAScriptViewの実験の続編です。#1ではSingle Windowのアプリを作って実験してみました(モノ自体は作ってあったので)。macOS 15.3 beta+Xcode 16.2でテストしました。

#2ではDocumentベースのアプリを作って、そこにOSAScriptViewを載せました。余計なテキストフィールドが載っているのは、いろいろ野望があるためです。

–> Download Fake Script Editor

#1と同様にコピペでAppleScriptを入力して、実際に動かして、結果を受け取れます。

ただし、この段階ですでに問題山積の状態です。Compile操作を行うと、ひさしぶりのビーチボール表示になって返ってきません。

Run Scriptはできるのに、Compile(Check Syntax)動作で落ちます。

この段階でかなり「どうすんの、これ?」という状態です。普通に部品を並べて普通につないで動かしたらクラッシュするというのは……

Posted in AppleScript Application on Xcode | Tagged 13.0savvy 14.0savvy 15.0savvy OSAScriptView | Leave a comment

OSAScriptViewのじっけん#1

Posted on 1月 9 by Takaaki Naganoya

OSASCriptViewを試してみましょう。自前でScript Editorをどの程度作れるのかという確認作業です。Xcode 16.2+macOS 15.3betaで確認を行なっています。

–> Download Xcode Project osascript_test

とはいえ、これは2017年にすでに調査してありました。OSASCriptControllerとOSAScriptViewをCocoa Bindingでつないで、さらにいくつかの必要なボタンをOSASCriptControllerにつないで、簡単なAppleScript記述+実行のテストプロジェクトを作成。

この実行環境は、AppleScriptライブラリを認識して呼び出せますし、OSの構文色分け設定を認識します。

ただし、Apple純正のスクリプトエディタ同様、Cocoa Objectのログ表示は行えません。

また、かなり致命的な問題なのですが、バンドル形式のAppleScriptはこの状態では編集・実行できません。

Appleが配布していたサンプルコードで、AppleScriptObjCが出たての頃にスクリプトエディタをASOCで組んだプロジェクトを見かけたのですが、それを探して編集するのが手っ取り早そうです。ただ、あれもバンドル形式のAppleScript書類を編集・実行できなかった記憶があります。

Posted in AppleScript Application on Xcode OSA | Tagged 13.0savvy 14.0savvy 15.0savvy OSAScriptController OSAScriptView | Leave a comment

指定フォルダ以下の画像のMD5チェックサムを求めて、重複しているものをピックアップしてダイアログでプレビュー_v4

Posted on 1月 2 by Takaaki Naganoya

指定フォルダ以下の画像(種別問わず)をすべてピックアップして、それぞれMD5チェックサムを計算し、重複しているものをピックアップしてデータとして出力するAppleScriptです。実行にはScript Debuggerを必要とします。今後は、ScriptableなライブラリをXcodeで1本作って、そこにAppleScriptから呼び出すのに便利なFrameworkを突っ込みまくるようにするのかも? 

–> Download Script Bundle within framework and library

前バージョンのScriptでは指定フォルダ直下の画像だけをピックアップするようになっていました、Spotlight検索でサブディレクトリ以下もすべて画像収集するように変更し、本Scriptだけで重複画像のブラウズができるようになっています。NSOutlineView+NSImageでブラウズするダイアログの部品はedama2さんから提供していただいています。

AppleScript名:指定フォルダ以下の画像のMD5チェックサムを求めて、重複しているものをピックアップしてダイアログでプレビュー_v4.scptd
— Created 2015-10-01 by Takaaki Naganoya
— Modified 2015-10-01 by Shane Stanley–With Cocoa-Style Filtering
— Modified 2018-12-01 by Takaaki Naganoya
— Modified 2024-12-19 by Takaaki Naganoya
— Modified 2025-01-01 by Takaaki Naganoya
— Modified 2025-01-02 by Takaaki Naganoya
use AppleScript
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "md5Lib" –https://github.com/JoeKun/FileMD5Hash
use outImageV : script "visLib" –NSOUtlineView+NSImageView Lib by edama2
use mdLib : script "Metadata Lib" version "2.0.0"

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSPredicate : a reference to current application’s NSPredicate
property NSCountedSet : a reference to current application’s NSCountedSet
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSString : a reference to current application’s NSString
property NSFileManager : a reference to current application’s NSFileManager
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor

script spd
  property fList : {}
  
property fRes : {}
  
property md5List : {}
  
property fmdList : {}
  
property dupRes : {}
  
property outList : {}
end script

set aFol to POSIX path of (choose folder)
–set aFol to POSIX path of (path to pictures folder)

set (fRes of spd) to mdLib’s searchFolders:{aFol} searchString:("(kMDItemContentTypeTree CONTAINS %@)") searchArgs:{"public.image"}

–すべての画像のMD5チェックサムを計算
set (md5List of spd) to {}
set (fmdList of spd) to {}

repeat with i in (fRes of spd)
  set j to contents of i
  
set md5Res to (current application’s FileHash’s md5HashOfFileAtPath:(j)) as string
  
set the end of (md5List of spd) to md5Res
  
set the end of (fmdList of spd) to {filePath:j, md5:md5Res}
end repeat

–チェックサムが重複している画像を取り出す
set fmdArray to NSArray’s arrayWithArray:(fmdList of spd)

set (dupRes of spd) to returnDuplicatesOnly((md5List of spd)) of me
set (outList of spd) to {}
set procMDs to {}
set aRecord to {}

repeat with i in (dupRes of spd)
  set j to contents of i
  
  
if j is not in procMDs then
    set aRes to filterDictArrayByLabel(fmdArray, "md5 == ’" & j & "’") of me
    
    
set tmpMD5 to filePath of (first item of aRes)
    
    
set tmpRes to {}
    
repeat with ii in aRes
      set jj to contents of ii
      
set idSrcURL to (current application’s NSURL’s fileURLWithPath:(filePath of jj))
      
set the end of tmpRes to {|name|:idSrcURL’s lastPathComponent(), fileURL:idSrcURL, isLeaf:true}
    end repeat
    
    
set aRec to {|name|:j, fileRes:"", isLeaf:false, children:tmpRes}
    
set aRecord’s end to aRec
    
set the end of procMDs to j
    
set the end of (outList of spd) to aRec
  end if
end repeat

–OutlineView+ ImageViewでダイアログ表示
set mainMes to "重複画像一覧"
set subMes to "指定フォルダ以下の重複画像は以下のとおりです"
set aRes to outImageV’s alert:mainMes informativeText:subMes treeData:(outList of spd) isExpand:true

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterDictArrayByLabel(aArray, aPredicate as string)
  –抽出
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
return filteredArray
end filterDictArrayByLabel

–指定フォルダ以下のすべてのファイルを再帰で取得
on retFullpathsWithinAFolderWithRecursive(aFol)
  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 as string)
  end repeat
  
  
return anArray as list
end retFullpathsWithinAFolderWithRecursive

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

on returnDuplicatesOnly(aList as list)
  set aSet to 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

★Click Here to Open This Script 

Posted in file Image | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

執筆中:AppleScript最新リファレンスver2.8対応(macOS 15対応アップデート)

Posted on 1月 1 by Takaaki Naganoya

「AppleScript最新リファレンスver2.8対応」をお買い上げの読者の方々に対して、アップデート版として提供されます。

ほとんどできているのですが、「AppleScript最新リファレンスver2.8対応」添付のPiyomaru Script Assistantに合わせて内容の調整を行なっています。macOS 15の登場によって変更になった箇所の情報を中心に内容を補っています。前バージョンからは60ページほど内容を追記しています。

同ツールは初版に添付することをねらっていましたが、macOSのバグ(とくにText To Speech系)の状況確認や対応に時間がかかっていました。

English Version is here.

English version will be updated as original version. At first, English version is devided 3 part. But English version did not make good sales as I expected, so #2 and #3 project will be canceled.

Posted in Books | Tagged 12.0savvy 13.0savvy 14.0savvy 15.0savvy | 1 Comment

執筆中:Cocoa Scripting Course #10 NSAttributedString

Posted on 1月 1 by Takaaki Naganoya

目下、執筆中なのがCocoa Scripting Courseの10巻、NSAttributedStringです。FoundationとAppKitに分かれて機能が分布しており、なかなか言及すべき内容が多いものです。

WebKitにも機能が分布していますが、ざっと見たかぎりではWebKitのNSAttributedStringはAppleScriptから呼び出せないものがほとんどのようなので、ここは無視してよいでしょう。

NSAttributedStringとHTML、そしてMarkdownとの間の変換機能などが最近のmacOSのアップデートで追加されているため、こちらもすぐには完成しないことでしょう。

Posted in Books | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

執筆中:スクリプトエディタ Scripting Book with AppleScript

Posted on 1月 1 by Takaaki Naganoya

あけましておめでとうございます。

目下執筆中なのが、「スクリプトエディタScripting Book with AppleScript」という本です。

AppleScriptでスクリプトエディタを操作してさまざまな処理を行うことをテーマに据えています。不可能を可能にする系の内容がぎっしり。割とカロリー高めな内容です。

スクリプトエディタはMac OS X 10.3か4のときにスクリプタブルになり、従来のCarbonではなくCocoaで書き直されました。生産性を向上させるためにスクリプトエディタを操作するScriptingはその頃から行なってきたのですが、ノウハウの総量は巨大なものの、これを必要としているユーザーがどの程度いるのか? という懸念から、まとめることをためらっていました。

ただ、まとめずに放置しておいては、有用なノウハウも風化してしまうため、この機会にまとめてみることにしたものです。

目下、400ページほど書いてみましたが、これはAppleScriptコマンドリファレンスを含んだものであり、記事ページについては「数ページの箇所もあれば数十ページの章もあって、バランスがよくない」といった印象です。

いったん寝かせて放っておくと、いい感じに発酵して(角がとれて)マイルドな味わいになるかもしれません。

Posted in Books | Tagged 13.0savvy 14.0savvy 15.0savvy | 2 Comments

choose fileで指定したsdefを読み込み、sdef中のサンプル(用例)を個別にHTML書き出しする

Posted on 12月 30, 2024 by Takaaki Naganoya

スクリプトエディタから書き出したsdefファイルを選択すると、指定の書き出し先フォルダにsdef内のAppleScriptサンプルをHTML形式で書き出すAppleScriptです(最初のバージョンでHTMLの実体参照デコード処理をハードコーディングしていたのを、Cocoaの機能を利用するよう書き換えました)。

スクリプトエディタでAppleScript用語辞書を表示させた状態で、ファイル書き出しすると個別のsdefファイルとして保存できます。この状態のsdefにアプリのバージョン番号を付加して、バージョン履歴として保存しています。

こうして保存しておいたsdef内のサンプルAppleScriptをHTMLとして書き出します。Pixelmator Proに58本のサンプルScriptが入っていたので、けっこうな分量になります。それを手作業で取り出すのは手間なので、Scriptで取り出すことにしました。

それを収集するために作ったのが本Scriptです。

本来、スクリプトエディタで表示(xinclude解消+レンダリング)させたsdefを処理させるAppleScriptで、いちいちxincludeの展開を行わせるのは無意味なのですが、本Scriptはもともと「アプリのBundle IDを指定してsdefのパスを求めて処理する」ようになっていたため、仕様がとがりすぎて汎用性がいまひとつだったので、「スクリプトエディタで書き出したsdefを処理」するように書き換えたという経緯があるためです。説明したら余計にわからなくなったような、、、、

AppleScript名:choose fileで指定したsdefを読み込み、sdef中のサンプル(用例)を個別にHTML書き出しする v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/12/31
—
–  Copyright © 2022-2024 Piyomaru Software, All Rights Reserved
—

use AppleScript
use framework "Foundation"
use framework "AppKit"
use scripting additions

set sdefAlias to (choose file of type {"com.apple.scripting-definition"} with prompt "書き出したSDEFを選択")
set sdefFullPath to (POSIX path of sdefAlias)

–SDEF読み込み(Xincludeの展開が必要な状態)
tell current application
  set theXML to read sdefAlias as «class utf8»
end tell

–NSXMLDocumentの生成、Xincludeを有効に
set {theXMLDoc, theError} to current application’s NSXMLDocument’s alloc()’s initWithXMLString:theXML options:(current application’s NSXMLDocumentXInclude) |error|:(reference)

set aDocStr to (theXMLDoc’s XMLData)
set aDocStr2 to (current application’s NSString’s alloc()’s initWithData:(aDocStr) encoding:(current application’s NSUTF8StringEncoding)) as string

set sampleList to (extractStrFromTo(aDocStr2, "<html>", "</html>") of me)
set sampleCount to length of sampleList
if sampleCount = 0 then return

set outFol to POSIX path of (choose folder with prompt "Select Output Folder")

set aCount to 1

repeat with i in sampleList
  set j to (contents of i)
  
  
if j is not equal to "" then
    set j1 to decodeCharacterReference(j) of me
    
set j2 to "<!DOCTYPE html><html><meta charset=utf-8><title>" & (aCount as string) & "</title><body>" & j1 & "</body></html>"
    
    
set wPath to outFol & (aCount as string) & ".html"
    
set fRes to writeToFileAsUTF8(j2, wPath) of me
    
if fRes = false then error
    
    
set aCount to aCount + 1
  end if
end repeat

–指定パスからアプリケーションのScriptabilityをbooleanで返す
on retAppSdefNameFromBundleIPath(appPath as string)
  set aDict to (current application’s NSBundle’s bundleWithPath:appPath)’s infoDictionary()
  
set aRes to aDict’s valueForKey:"OSAScriptingDefinition"
  
if aRes = missing value then return false
  
set asRes to aRes as string
  
  
return asRes as string
end retAppSdefNameFromBundleIPath

–指定文字と終了文字に囲まれた内容を抽出
on extractStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set anArray to current application’s NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(reference)
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(reference)
    
if theValue is missing value then set theValue to "" –>追加
    
theScanner’s scanString:toStr intoString:(missing value)
    
anArray’s addObject:theValue
  end repeat
  
  
return (anArray as list)
end extractStrFromTo

on writeToFileAsUTF8(aStr, aPath)
  set cStr to current application’s NSString’s stringWithString:aStr
  
set thePath to POSIX path of aPath
  
set aRes to cStr’s writeToFile:thePath atomically:false encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
  
return aRes as boolean
end writeToFileAsUTF8

–文字置換
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

–実体参照をデコード
on decodeCharacterReference(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set theData to anNSString’s dataUsingEncoding:(current application’s NSUTF16StringEncoding)
  
set styledString to current application’s NSAttributedString’s alloc()’s initWithHTML:theData documentAttributes:(missing value)
  
set plainText to (styledString’s |string|()) as string
  
return plainText
end decodeCharacterReference

★Click Here to Open This Script 

Posted in file File path sdef XML | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

Cocoa Scripting Course用、タイトルの丸つき数字から表を編集 v2(複数スライド選択用)

Posted on 12月 23, 2024 by Takaaki Naganoya

Keynote書類で、タイトルに入っている丸つき数字を取得して、同スライド内にある「表」の行数を追加し、追加したヘッダーカラムに丸つき数字を追加するAppleScriptです。Cocoa Scripting Courseで手間のかかるページの作業を効率化するために作成しました。

本ScriptはKeynote 14.3で作成していますが、とくにあたらしめの機能は使っていないため、かなり古いバージョンに対しても使えるはずです。


▲処理前


▲処理後 表の行数が変更されている

Keynoteの現在表示中のスライドからテキストを抽出し、そこから丸つき数字の文字だけを取り出します。

それぞれの丸つき数字文字を数値に変換し、最大値を求めます。この最大値と表の行数を比較。表で足りない行数を計算して、表に行を新規追加。カラムヘッダーに丸つき数字を補います。

こうした処理を選択中の複数のスライド(ページ)に対して実行します。

表の「中身」についても、実際にスライド上に配置しているので自動で抽出できてもよさそうですが、そこに時間をかけても仕方がないのでいまはこのままです。あとで、そういう処理ができるようになるかもしれません。

AppleScript名:Cocoa Scripting Course用、タイトルの丸つき数字から表を編集 v2(複数スライド選択用).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/12/23
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

tell application "Keynote"
  tell front document
    set sSel to selection
    
if class of first item of sSel is not equal to slide then return
    
    
repeat with curSlide in sSel
      set current slide to curSlide
      
      
tell current slide
        –タイトルから丸つき数字文字のみ抽出
        
set myTitle to object text of default title item
        
set numStr to holdNumberWithSignOnly(myTitle) of me
        
set numList to characters of numStr
        
        
–丸つき数字のうち最大のものを取得
        
set cList to {}
        
repeat with i in numList
          set j to decodeNumFromNumWithSign(i) of me
          
set the end of cList to j
        end repeat
        
        
set sList to shellSortDescending(cList) of me
        
set theLargestNum to first item of sList –最大値
        
        
        
–表の情報を取得
        
tell table 1
          set rCount to count every row
          
set tHeight to height of it
        end tell
        
        
–追加が必要な行数を算出
        
set addRows to theLargestNum + 2 – rCount
        
if addRows > 0 then
          tell table 1
            set row count to (rCount + addRows)
            
            
repeat with i from (rCount – 1) to (rCount + addRows – 2)
              tell row (i + 1)
                tell cell 1
                  set value to convNumToNumWithSign(i) of me
                end tell
              end tell
            end repeat
            
            
tell row -1
              tell cell 1
                set value to "返り値"
              end tell
            end tell
            
            
–Resize Heiight
            
set curRows to row count
            
set height to (tHeight / rCount) * curRows
          end tell
        end if
      end tell
    end repeat
  end tell
end tell

–文字列から丸つき数字のみ抽出
on holdNumberWithSignOnly(aStr as text)
  set aNSString to current application’s NSString’s stringWithString:aStr
  
  
return (aNSString’s stringByReplacingOccurrencesOfString:"[^\\U000024EA-\\U000024EA\\U00002460-\\U00002473\\U00003251-\\U000032BF\\U000024FF-\\U000024FF\\U00002776-\\U0000277F\\U000024EB-\\U000024F4\\U00002780-\\U00002789\\U0000278A-\\U00002793\\U000024F5-\\U000024FE]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, aNSString’s |length|()}) as text
end holdNumberWithSignOnly

–丸つき数字を数字に変換
on decodeNumFromNumWithSign(aStr as string)
  set numStr to "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿"
  
if numStr does not contain aStr then return false
  
using terms from scripting additions
    set bNum to offset of aStr in numStr
  end using terms from
  
return bNum
end decodeNumFromNumWithSign

–数字を丸つき数字に変換
on convNumToNumWithSign(aNum as number)
  if (aNum ≤ 0) or (aNum > 50) then return ""
  
set aStr to "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿"
  
set bChar to character aNum of aStr
  
return bChar
end convNumToNumWithSign

–入れ子ではないリスト(1D List)の昇順ソート
on shellSortAscending(aSortList)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap ≤ len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len – 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j ≥ gap) and (oBj’s list’s item (j – gap + 1) > temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j – gap + 1)
          
set j to j – gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortAscending

–入れ子ではないリスト(1D List)の降順ソート
on shellSortDescending(aSortList)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap ≤ len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len – 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j ≥ gap) and (oBj’s list’s item (j – gap + 1) < temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j – gap + 1)
          
set j to j – gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortDescending

★Click Here to Open This Script 

Posted in Text | Tagged 13.0savvy 14.0savvy 15.0 Keynote | Leave a comment

指定フォルダ以下の画像のMD5チェックサムを求めて、重複しているものをピックアップ

Posted on 12月 19, 2024 by Takaaki Naganoya

指定フォルダ以下の画像(種別問わず)をすべてピックアップして、それぞれMD5チェックサムを計算し、重複しているものをピックアップしてデータとして出力するAppleScriptです。実行にはScript Debuggerを必要とします。内蔵のMD5計算Frameworkはx64/Apple Silicon(ARM64E)のUniversal Binaryでビルドしてあります。

–> –> Download photoDupLister(Script Bundle with Framework in its bundle)

# 本Scriptのファイル収集ルーチンが、再帰で下位フォルダの内容をすべてピックアップするものではありませんでした
# 実際に指定フォルダ以下すべての画像を収集する(Spotlightで)ようにしてみたら5.5万ファイルの処理に26分ほどかかりました

MD5チェックサムが同じということは、同じ画像である可能性が高いものです。

ここで、各画像のチェックサムを計算するさいに、サムネイルを生成してからチェックサムを計算するかどうかという話があります。

サムネイルを作成すべき派の言い分は、そのほうが計算量が減らせるし、同一画像の縮尺違い(拡大/縮小率違い)を求めることもできるというものです。

サムネイル作成否定派の言い分は、そんなもん作る前に画像のチェックサムを計算してしまえ、逆に手間だというものでした。

これは、どちらの意見ももっともだったので、実際にシミュレーションを行ってみるしかないでしょう。そこで、ありもののルーチンを集めて実際に作ってみたのが本Scriptです。サムネイルは作らないで処理してみました。

自分のMacBook Air M2のPicturesフォルダに入っていた約5,000の画像ファイルを処理したところ、16ペアの重複画像がみつかりました。処理にかかる時間はおよそ9秒です(実行するたびに所要時間が若干変化)。おそらく、Intel Macで実行すると数十秒から数分かかるのではないかと。

実用性を確保したい場合には、画像を回転しつつチェックサムを1画像あたり4パターン求めるとか、やはり同じサイズのサムネイル画像を生成してサムネイルに対してMD5チェックサムを計算するとか、画像の類似度を計算するオプションなども欲しいところです。

また、処理内容が並列処理向きなので、並列で処理してみてもよいでしょう。マシン環境を調べてSoCのPコアの個数をかぞえて、Pコアと同数の処理アプレットを生成して並列実行。……余計な処理を行うせいで速くならない可能性が高そうです。

AppleScript名:指定フォルダ以下の画像のMD5チェックサムを求めて、重複しているものをピックアップ
— Created 2015-10-01 by Takaaki Naganoya
— Modified 2015-10-01 by Shane Stanley–With Cocoa-Style Filtering
— Modified 2018-12-01 by Takaaki Naganoya
— Modified 2024-12-19 by Takaaki Naganoya
use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "md5Lib" –https://github.com/JoeKun/FileMD5Hash

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSPredicate : a reference to current application’s NSPredicate
property NSCountedSet : a reference to current application’s NSCountedSet
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey

script spd
  property fList : {}
  
property fRes : {}
  
property md5List : {}
  
property fmdList : {}
  
property dupRes : {}
  
property outList : {}
end script

set anUTI to "public.image"

set aFol to choose folder
–set aFol to path to pictures folder

set (fList of spd) to getFilePathList(aFol) of me

–指定のFile listのうち画像のみ抽出
set (fRes of spd) to filterAliasListByUTI((fList of spd), "public.image") of me
if (fRes of spd) = {} then return

–すべての画像のMD5チェックサムを計算
set (md5List of spd) to {}
set (fmdList of spd) to {}

repeat with i in (fRes of spd)
  set j to contents of i
  
set md5Res to (current application’s FileHash’s md5HashOfFileAtPath:(j)) as string
  
set the end of (md5List of spd) to md5Res
  
set the end of (fmdList of spd) to {filePath:j, md5:md5Res}
end repeat

–チェックサムが重複している画像を取り出す
set fmdArray to NSArray’s arrayWithArray:(fmdList of spd)

set (dupRes of spd) to returnDuplicatesOnly((md5List of spd)) of me
set (outList of spd) to {}
set procMDs to {}

repeat with i in (dupRes of spd)
  set j to contents of i
  
  
if j is not in procMDs then
    set aRes to filterDictArrayByLabel(fmdArray, "md5 == ’" & j & "’") of me
    
    
set tmpMD5 to filePath of (first item of aRes)
    
    
set tmpRes to {}
    
repeat with ii in aRes
      set jj to contents of ii
      
set the end of tmpRes to filePath of jj
    end repeat
    
    
set aRec to {md5:j, fileRes:tmpRes}
    
set the end of (outList of spd) to aRec
    
set the end of procMDs to j
  end if
end repeat

return (outList of spd)

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterDictArrayByLabel(aArray, aPredicate as string)
  –抽出
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
  
–NSArrayからListに型変換して返す
  
set bList to filteredArray as list
  
return bList
end filterDictArrayByLabel

on getFilePathList(aFol)
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of aFol)
  
set aFM to current application’s NSFileManager’s defaultManager()
  
set urlArray to aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:(current application’s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
  
return urlArray as anything
end getFilePathList

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

on returnDuplicatesOnly(aList as list)
  set aSet to 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

★Click Here to Open This Script 

Posted in check sum file Image UTI | Tagged 12.0savvy 13.0savvy 14.0savvy 15.0savvy | Leave a comment

MD5, SHA-1, SHA-3などのチェックサムを計算する

Posted on 12月 19, 2024 by Takaaki Naganoya

md5、sha-1、sha-3などのチェックサムを計算するAppleScriptです。

AppleScript、といいつつ、これらの処理の主体はすべてObjective-Cで書かれたプログラム(を、Cocoa Framework化したもの)です。

この種類の、ファイルの内容をすべて加算して計算するような処理は、インタプリタ型言語であるAppleScriptは苦手な処理です。何か、頭を使って処理量を減らすような工夫が通じません。

その結果、これらのScriptはScript Debugger上か、Script Debuggerから書き出したEnhanced Applet、その他のFramework呼び出しをサポートしているいくつかのAppleScript実行環境でしか実行できません。

Xcodeを用いてGUIなしヘルパーアプリを作って、他のAppleScript実行環境から呼び出しやすいようにSDEFを介して動かすようにすることも可能ですが、フリーで配布するほどの何かがあるわけでもありません。

なので、現状はこのままです。これらすべてのFrameworkを各ユーザー環境の~/Library/Frameworksフォルダにインストールして使用してください。x64/ARM64EのUniversal Binaryでビルドしてあります。

–> Download md5Lib.framework(To ~/Libraries/Frameworks)

–> Download md5FromDataKit.framework(To ~/Libraries/Frameworks)

–> Download SHA3Kit.framework(To ~/Libraries/Frameworks)

AppleScript名:ファイルのMD5、SHA1、SHA512のハッシュ値を求める
— Created 2016-02-11 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "md5Lib" –https://github.com/JoeKun/FileMD5Hash

set aPath to POSIX path of (choose file)

set a to (current application’s FileHash’s md5HashOfFileAtPath:aPath) as string
–>  "329e854b9993405414c66faac0e80b86"

set b to (current application’s FileHash’s sha1HashOfFileAtPath:aPath) as string
–>  "50847286df61f304d142c6a0351e39029f010fc2"

set c to (current application’s FileHash’s sha512HashOfFileAtPath:aPath) as string
–>  "5132a7b477652db414521b36……..1a6ff240e861752c"
return {a, b, c}

★Click Here to Open This Script 

AppleScript名:NSStringからSHA-3のハッシュ値を求める
— Created 2017-08-09 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "SHA3Kit" –https://github.com/jaeggerr/NSString-SHA3

set origData to (current application’s NSString’s stringWithString:"hello")
set aHash1 to (origData’s sha3:256) as string
–> "1C8AFF950685C2ED4BC3174F3472287B56D9517B9C948127319A09A7A36DEAC8"

set aHash2 to (origData’s sha3:224) as string

set aHash3 to (origData’s sha3:384) as string

set aHash4 to (origData’s sha3:512) as string

★Click Here to Open This Script 

AppleScript名:NSDataからMD5値を計算する
— Created 2016-02-11 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "md5FromDataKit" –https://github.com/siuying/NSData-MD5

set aStr to "ぴよまるソフトウェア"
set aNSStr to current application’s NSString’s stringWithString:aStr
set aData to aNSStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
set aMD5Hex to (current application’s NSData’s MD5HexDigest:aData) as string
–>  "2d0b4e205f274f20b17dc8ca4870f1db"

set aMD5 to (current application’s NSData’s MD5Digest:aData)’s |description|() as string
–>  <2d0b4e20 5f274f20 b17dc8ca 4870f1db>

★Click Here to Open This Script 

Posted in check sum | Tagged 11.0savvy 12.0savvy 13.0savvy 14.0savvy 15.0savvy | Leave a comment

2024年に書いた価値あるAppleScript

Posted on 12月 17, 2024 by Takaaki Naganoya

2024年に使用していたmacOS:macOS 13+macOS 15

毎年行なっている、Piyomaru Softwareが書いたAppleScriptの1年を振り返る記事の2024年版です。

2008年から10年ほど運営を続けてきた旧「AppleScriptの穴」Blogが2018年の年初にホスティング会社との行き違いでシャットダウンされ、ゼロから再構築したのがこの現行の「AppleScriptの穴」Blogです。

→ 2018年に書いた価値あるAppleScript
→ 2019年に書いた価値あるAppleScript
→ 2020年に書いた価値あるAppleScript
→ 2021年に書いた価値あるAppleScript
→ 2022年に書いた価値あるAppleScript
→ 2023年に書いた価値あるAppleScript

旧「AppleScriptの穴」Blogの内容については、データベースから抜き出したデータをもとに再構成した「Blogアーカイブ本」にまとめています。

AppleScriptの穴Blogアーカイブvol.1
AppleScriptの穴Blogアーカイブvol.2
AppleScriptの穴Blogアーカイブvol.3
AppleScriptの穴Blogアーカイブvol.4
AppleScriptの穴Blogアーカイブvol.5
AppleScriptの穴Blogアーカイブvol.6

本Blogは、もともとは、2000年代初頭に開発していた「人工知能インタフェース Newt On」のソースコード部品バラバラにして掲載し、用いた部品を個別にメンテナンスすることを「隠れた目的」としていました。また、Scripter間のノウハウの共有を推進することも目的としています。

AppleScript以外の一般的なテーマの記事については、こちらにいろいろ投稿しています。

https://note.com/140software/

前述のとおり、2018年1月にいちど本Blogは消えていました。その際に、「本Blogが存在しない場合にはどのような現象が起こるのか」を観察。その結果、AppleScriptについて知識を持たない人たちが好き勝手に「嘘」を流布しはじめる、という現象が観測されました。本Blogはそうした「嘘つき」を封じ込めるためのキーストーンとしての役割を果たしているといえます。

電子書籍の発行状況

本Blogを公開しているだけでは、ホスティング費用やドメイン費用がかかるだけで、何も収益が生まれません。そこで、本Blog+αの情報を整理してまとめた電子書籍を発行しています。本Blog読者のみなさまにおかれては、電子書籍を購入することで本Blog運営を支えていただけますと幸いです。

電子書籍の2024年における刊行は、現時点で95冊。年間8冊となっています。

Cocoa Scripting Course #7 NSColor
Cocoa Scripting Course #8 File path Processing
Cocoa Scripting Course #9 File Processing
AppleScriptでたのしむ レトロ・グラフィックス プログラム集
Pages+AppleScriptで本をつくろう!
AppleScript基礎テクニック集(32)複数のアプリをコントロール
AppleScript基礎テクニック集(33)選択中のオブジェクト取得
AppleScript 基礎テクニック集(34)電源制御

目下、既刊本の最新環境へのアップデートを実行中です。

2024年に書いたAppleScriptの中で注目すべきもの

余白トリミング実験 v3

余白トリミング実験 v3

2024年に書いたScriptのうちで一番気合いが入っているのが、この画像の余白トリミングです。AppleScriptでそんな画像処理ができるとは思ってもいませんでしたが、実際にやってみたらそれなりに機能して、それなりの速度で動きました。

Outline View Lib

Outline View Lib

NSOutlineViewを手軽に使えるライブラリです。他のアプリで作った階層データ(Keynoteのマスターページ名など)をプレビューするなどの用途に使えます。

書式つきテキストを組み立てて、画像を追加し、RTFDとして保存 v2

書式つきテキストを組み立てて、画像を追加し、RTFDとして保存 v2

電子書籍用にまとめていたScriptの中のひとつです。RTFDの新規保存については書いたことがなかったので、「書いておいたほうがよいだろう」と。同様にScptd(バンドル形式AppleScript)の作成Scriptも書いておきたいところ&scptdの実行Script(Script Viewを自前で作成して)も書いておきたいところですが、公表されているAPIの範囲では実行できるものが見当たりません。

アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v4

アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v4

これも、ずいぶん前に試作品を見ていたのですが、前バージョンが動かなくなって久しかったのでアップデートしておきました。あくまで、デモ用で実用性が皆無ですが、そういうものなんでしょう。

Pagesで、現在表示中のページから離れたページのオブジェクト情報を取得できない

Pagesで、現在表示中のページから離れたページのオブジェクト情報を取得できない

Pagesが怪奇現象を起こすことについては、ずいぶん前から知っていたのですが、その発生条件と範囲を明確にできたことは意義深いことです。

指定のSDEFファイルからコマンドを抽出

指定のSDEFファイルからコマンドを抽出

SDEF処理系AppleScriptはいろいろ組んでいますが、電子書籍作成時にアプリのアップデート履歴を表で示すためにこうしたScriptが必要です。

Chat GPTに書かせたQuickSort(昇順・降順ソート)2D

Chat GPTに書かせたQuickSort(昇順・降順ソート)2D

ChatGPTに書かせたAppleScriptです。バージョン依存しなかったり、他の言語で書いてあるものを翻訳するようなScriptだと割とまともなAppleScriptを出力してくれます。ただし、高速化の余地があるレベルの(遅い)Scriptだったので、自前で高速化してみました。

Excel__Numbersセルアドレスの相互変換

Excel__Numbersセルアドレスの相互変換

ChatGPTに書かせたAppleScriptです。こちらも、OSのバージョンに依存せず、他の言語でも書ける内容だったので、問題なく処理できるScriptが出力されました。

Posted in news | Tagged 13.0savvy 15.0savvy | Leave a comment

指定言語でNLEmbeddingを処理できるかチェック_13_14_15

Posted on 12月 16, 2024 by Takaaki Naganoya

NaturalLanguage.frameworkのごくごく入門的なオブジェクト「NLEmbedding」を利用できるか、各言語でチェックを行ったところ、macOS 13、14で予想外の結果が返ってきた内容をmacOS 15で再確認してみました。

ラテン系言語を中心に中国語がサポートされているあたりがあまりにも特徴的なNaturalLanguage.framework。多くの機能を日本語で利用できないことは分かりきっていたのですが、macOS 14で対応言語が激減。このまま廃止されるのかと驚いていたのですが、macOS 15で復旧していました。

どうしてmacOS 14.x台で復旧していなかったのか。ひたすら不思議です。

AppleScript名:指定言語でNLEmbeddingを処理できるかチェック_13_14_15.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/03/13
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.8"
use framework "Foundation"
use framework "NaturalLanguage"
use scripting additions

–The result is on macOS 13.6.5 / 14.4 / 15.2
set aRes to testNLLanguage("NLLanguageEnglish") of me –> true–> true –true
set aRes to testNLLanguage("NLLanguageFrench") of me –> true–>false (macOS 14)—> true
set aRes to testNLLanguage("NLLanguageGerman") of me –> true–>false (macOS 14)–> true
set aRes to testNLLanguage("NLLanguageItalian") of me –> true–>false (macOS 14)–> true
set aRes to testNLLanguage("NLLanguagePortuguese") of me –> true–>false (macOS 14)–> true
set aRes to testNLLanguage("NLLanguageSimplifiedChinese") of me –> true–>false (macOS 14)–> true
set aRes to testNLLanguage("NLLanguageSpanish") of me –> true–>false (macOS 14)–> true

set aRes to testNLLanguage("NLLanguageUndetermined") of me –> true –>Natural Language framework doesn’t recognize(macOS 14).–> true
–macOS 14.7.2で再確認したところtrueに

set aRes to testNLLanguage("NLLanguageAmharic") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageArabic") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageArmenian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageBengali") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageBulgarian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageBurmese") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageCatalan") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageCherokee") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageCroatian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageCzech") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageDanish") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageDutch") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageFinnish") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageGeorgian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageGreek") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageGujarati") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageHebrew") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageHindi") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageHungarian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageIcelandic") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageIndonesian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageJapanese") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageKannada") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageKazakh") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageKhmer") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageKorean") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageLao") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageMalay") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageMalayalam") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageMarathi") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageMongolian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageNorwegian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageOriya") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguagePersian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguagePolish") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguagePunjabi") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageRomanian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageRussian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageSinhalese") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageSlovak") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageSwedish") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageTamil") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageTelugu") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageThai") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageTibetan") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageTraditionalChinese") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageTurkish") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageUkrainian") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageUrdu") of me –> false–> false–> false
set aRes to testNLLanguage("NLLanguageVietnamese") of me –> false–> false–> false

on testNLLanguage(aLangName)
  set aText to "use AppleScript
use framework \"Foundation\"
use framework \"NaturalLanguage\"

  set targLang to (current application’s " & aLangName & ")
  set aEmb to current application’s NLEmbedding’s wordEmbeddingForLanguage:(targLang)
  if aEmb = missing value then return false
  return true
  "

  
return run script aText
end testNLLanguage

★Click Here to Open This Script 

Posted in Natural Language Processing | Tagged 13.0savvy 14.0savvy 15.0savvy NLEmbedding | Leave a comment

Outline View Lib

Posted on 12月 16, 2024 by Takaaki Naganoya

AppKit系のオブジェクトで最難関との呼び声も高い、NSOutlineViewをAppleScriptから呼び出しやすく機能をまとめたものです。

edama2さんと数年前に「Outline Viewがどうにかならないものか」と相談し、まとめていただいたものです。本当はもっとシンプルに書いてあったのですが、データを外部から指定できるようにしたり、デフォルト状態でNSOutlineViewを展開状態で表示する機能を追加したり、行ごとの背景色を変更できるようにしたり……と、機能が増えました。

本UIをAppleScript上で利用する用途は、データ選択や階層データのプレビュー(PDFのTOCなど)などです。

NSTreeControllerの使い方だったり、Cocoa Bindingをプログラマティックに実行していたりと、そのあたりが見どころでしょう。

スクリプトエディタとScript Debuggerの両方で動作確認していますし、スクリプトメニュー上で動作しています。
CotEditorの内蔵スクリプトメニューに入れたところ最前面にダイアログ表示されませんでした。

AppleScript名:Outline View Lib.scpt
—
–  Created by: edama2 & Piyomaru
–  Created on: 2024/12/16
—
–  Copyright © 2024 edama2 & Piyomaru, All Rights Reserved
—

use AppleScript
use framework "Cocoa"

property dRes : missing value –Selection
property _data_source : missing value

set aRecord to {}
set aRecord’s end to {|name|:"🟥 格闘機", isLeaf:false, children:{{|name|:"RGM-79(G)陸戦型ジム", isLeaf:true}, {|name|:"RB-79KボールK型", isLeaf:true}, {|name|:"RGM-79Lジム・ライトアーマー", isLeaf:true}, {|name|:"RGM-79ジム(指揮官機)", isLeaf:true}, {|name|:"RGM-79FPジム・ストライカー", isLeaf:true}, {|name|:"RGM-79Vジム・ナイトシーカー", isLeaf:true}, {|name|:"RX-77-3ガンキャノン重装型", isLeaf:true}, {|name|:"RX-78XXピクシー", isLeaf:true}}}
set aRecord’s end to {|name|:"🟧 近距離機", isLeaf:false, children:{{|name|:"RGM-79ジム", isLeaf:true}, {|name|:"TGM-79ジム・トレーナー", isLeaf:true}, {|name|:"RAG-79アクア・ジム", isLeaf:true}, {|name|:"RGM-79ジム(WD隊)", isLeaf:true}, {|name|:"MS-06F-2ザクII(F2)", isLeaf:true}}}
set aRecord’s end to {|name|:"🟩 射撃型機", isLeaf:false, children:{{|name|:"RGC-80Sジム・キャノン(空間突撃仕様)", isLeaf:true}, {|name|:"RGM-79Fデザート・ジム", isLeaf:true}, {|name|:"RX-79(G)陸戦型ガンダム(ジム頭)", isLeaf:true}}}
set aRecord’s end to {|name|:"🟪 支援型機", isLeaf:false, children:{{|name|:"RGM-79SCジム・スナイパーカスタム", isLeaf:true}, {|name|:"RGM-79SCジム・スナイパーカスタム(SP)", isLeaf:true}, {|name|:"RX-77-2ガンキャノン", isLeaf:true}, {|name|:"RGM-79SPジム・スナイパーII", isLeaf:true}, {|name|:"FA-78-2ヘビーガンダム", isLeaf:true}, {|name|:"FA-78-1フルアーマーガンダム", isLeaf:true}}}
set aRecord’s end to {|name|:"🟦 遠距離型機", isLeaf:false, children:{{|name|:"RB-79ボール", isLeaf:true}, {|name|:"RGM-79(G)ジム・スナイパー", isLeaf:true}, {|name|:"RGC-80ジム・キャノン", isLeaf:true}, {|name|:"RX-75量産型ガンタンク", isLeaf:true}, {|name|:"RGC-80ジム・キャノン(WD隊)", isLeaf:true}, {|name|:"RTX-440陸戦強襲型ガンタンク", isLeaf:true}, {|name|:"RX-75ガンタンク", isLeaf:true}, {|name|:"RX-77D量産型ガンキャノン", isLeaf:true}, {|name|:"FA-78-1Bフルアーマーガンダム(TYPE-B)", isLeaf:true}}}

set mainMes to "戦場の絆MS選択"
set subMes to "以下のリストから希望の機体を選択してください"

set aRes to displayOutline(aRecord, mainMes, subMes, true, 400, 700) of me

on displayOutline(treeData, messageText, informativeText, isExpand, aWidth, aHeight)
  set (my _data_source) to missing value –init
  
set paramObj to {treeData:treeData, messageText:messageText, informativeText:informativeText, isExpand:isExpand, aWidth:aWidth, aHeight:aHeight}
  
my performSelectorOnMainThread:"raizeAlert:" withObject:(paramObj) waitUntilDone:true
  
return dRes
end displayOutline

on raizeAlert:paramObj
  –Initialize return value
  
set dRes to missing value
  
  
–Recieve Parameters
  
set treeData to (treeData of paramObj) as list
  
set messageText to (messageText of paramObj)
  
set informativeText to (informativeText of paramObj)
  
set isExpand to (isExpand of paramObj) as boolean
  
set aWidth to (aWidth of paramObj) as integer
  
set aHeight to (aHeight of paramObj) as integer
  
  
–Make Accessory View
  
set accessoryView to makeAccessoryView(treeData, isExpand, aWidth, aHeight) of me
  
  
tell current application’s NSAlert’s new()
    current application’s NSApplication’s sharedApplication()’s setActivationPolicy:(current application’s NSApplicationActivationPolicyRegular)
    
current application’s NSApp’s activateIgnoringOtherApps:(true)
    
    
setMessageText_(messageText)
    
setInformativeText_(informativeText)
    
setAccessoryView_(accessoryView)
    
runModal()
  end tell
  
  
set selectedObject to (my _data_source)’s selectedObjects()’s firstObject()
  
set dRes to {selectedObjects:selectedObject as {record, anything}}
end raizeAlert:

on makeAccessoryView(treeData as list, isExpand as boolean, aWidth as integer, aHeight as integer)
  set my _data_source to current application’s NSTreeController’s alloc()’s initWithContent:treeData
  (
my _data_source)’s setChildrenKeyPath:"children"
  (
my _data_source)’s setLeafKeyPath:"isLeaf"
  
  
set scrollView to (current application’s NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)))
  
  
tell (current application’s NSOutlineView’s alloc()’s initWithFrame:(current application’s NSZeroRect))
    addTableColumn_(current application’s NSTableColumn’s alloc()’s initWithIdentifier:"name")
    
bind_toObject_withKeyPath_options_(current application’s NSContentBinding, (my _data_source), "arrangedObjects", missing value)
    
bind_toObject_withKeyPath_options_(current application’s NSSelectionIndexPathsBinding, (my _data_source), current application’s NSSelectionIndexPathsBinding, {})
    
    
expandItem_expandChildren_(missing value, isExpand)
    
scrollView’s setDocumentView:it
    
setHeaderView_(missing value)
    
setOutlineTableColumn_(tableColumns()’s firstObject())
    
setUsesAlternatingRowBackgroundColors_(true)
    
    
tell tableColumns()’s firstObject()
      bind_toObject_withKeyPath_options_(current application’s NSValueBinding, (my _data_source), ("arrangedObjects." & its identifier()), missing value)
      
setTitle_(its identifier())
      
setWidth_(current application’s NSWidth(tableView()’s superview()’s |bounds|()))
    end tell
  end tell
  
  
return scrollView
end makeAccessoryView

★Click Here to Open This Script 

Posted in dialog | Tagged 12.0savvy 13.0savvy 14.0savvy 15.0 NSAlert NSApplication NSContentBinding NSMakeRect NSOutlineView NSSelectionIndexPathsBinding NSTableColumn NSTreeController | Leave a comment

Bluetoothに接続中のデバイス名を取得するv6

Posted on 12月 13, 2024 by Takaaki Naganoya

3年ぐらい前に書いてあった、Mac本体にペアリングして接続しているBluetoothのデバイス名を取得するAppleScriptです。

AppleScript名:Bluetoothに接続中のデバイス名を取得するv6.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/12/13
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "IOBluetooth"

set pRes to getBluetoothPowerState() of me
if pRes = false then return

set dArray to current application’s IOBluetoothDevice’s pairedDevices()
set dRes to my filterRecListByLabel1(dArray, "isConnected != 0")
set dNameList to (dRes’s valueForKeyPath:"name") as list
–> {"Logicool Z600", "Takaaki Naganoya のキーボード #1", "Takaaki Naganoya のマウス"}
–> {"Logicool Z600", "AirPods Pro", "DUALSHOCK 4 Wireless Controller"}

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
return filteredArray
end filterRecListByLabel1

–Mac本体のBluetoothのパワー状態を取得
on getBluetoothPowerState()
  set aCon to current application’s IOBluetoothHostController’s alloc()’s init()
  
set pRes to (aCon’s powerState()) as boolean
end getBluetoothPowerState

★Click Here to Open This Script 

Posted in Bluetooth System | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

Skim v1.7.6でopen locationコマンドを実装するも動作せず

Posted on 12月 12, 2024 by Takaaki Naganoya

オープンソースのPDFリーダー「Skim」のバージョン1.7.6において「open location」コマンドが実装されましたが、実際に試してみると動きません。確認は最新版の1.7.7で行いました。

これまでにも追加したコマンドを次のバージョンで廃止して、翌々バージョンで復活させたりと、いろいろその歴史をひもとくと「おっとっと」な動きが見られるので、そういうものなんでしょう。

本Blog上に存在するPDFのURLを指定。open locationでダウンロード+表示を試みるものの、表示されずにエラーになる。

→ Skimが「http://」をサポートしていないとのこと。https://からのダウンロードおよび表示は確認しました。

AppleScript名:Skim v17.6で追加されたopen locationのテスト.scpt
set aURL to "http://piyocast.com/as/wp-content/uploads/2018/09/GUNDAM-UI.pdf"

tell application "Skim"
  set erRes to (open location aURL with error reporting)
end tell

★Click Here to Open This Script 

Posted in Bug | Tagged 13.0savvy 14.0savvy 15.0savvy Skim | Leave a comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • CotEditorで2つの書類の行単位での差分検出
  • macOS 15, Sequoia
  • 指定のWordファイルをPDFに書き出す
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • AppleScriptによる並列処理
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • Cocoa Scripting Course 続刊計画
  • macOS 14.xでScript Menuの実行速度が大幅に下がるバグ
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • NaturalLanguage.frameworkでNLEmbeddingの処理が可能な言語をチェック
  • Keynote/Pagesで選択中の表カラムの幅を均等割
  • Keynote、Pages、Numbers Ver.14.0が登場
  • macOS 15 リモートApple Eventsにバグ?
  • デフォルトインストールされたフォント名を取得するAppleScript
  • AppleScript入門① AppleScriptってなんだろう?

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (194) 14.0savvy (146) 15.0savvy (128) CotEditor (66) Finder (51) iTunes (19) Keynote (116) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (76) Pages (54) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • date
  • dialog
  • diff
  • drive
  • Droplet
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 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月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

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