JXA」タグアーカイブ

osascript Filenames

今回は osascript でファイル名関連をば。

OS?X 10.10 Release Notes

を見つけてやっと Objective-C からの変換方法が解ってきた。
物凄く下のほうにあって見つけにくかったよ。
たとえばこんなふうに引数が二つ以上の場合は先頭を大文字にして合体。

/*
contentsOfDirectoryAtPath:error:
to
contentsOfDirectoryAtPathError
*/

fm = $.NSFileManager.defaultManager
files = fm.contentsOfDirectoryAtPathError(pathB, null)

– fileExistsAtPath:isDirectory: – NSFileManager Class Reference

つまり Objective-C の文法を少し理解していないと変換すらできない。
コロンって引数だったのか、解ってしまえば楽勝だけど。

ディレクトリ内容列挙は NSFileManager でできるようだ。
ということでコードを書いてみる。
実は var とセミコロンはいらないけどキモいので書くことにした。

#!/usr/bin/osascript

ObjC.import("Cocoa");

// NSString
var pathA = $.NSString.alloc.initWithString("~/Documents/");
// ~ to $HOME
var pathB = pathA.stringByExpandingTildeInPath;
console.log("Path @ " + pathB.UTF8String);
// to URI
var uri = $.NSURL.fileURLWithPath(pathB);
console.log("URI @ " + uri.absoluteString.UTF8String);

// FileManager
var fm = $.NSFileManager.defaultManager;
// get files
var files = fm.contentsOfDirectoryAtPathError(pathB, null);
for (var i=0; i<files.count; i++) {
    // error files[i]
    var filename = files.objectAtIndex(i).UTF8String;
    // remove dot file
    if (filename[0] != ".") {
        console.log(filename);
    }
}

おかげで気が付いた、NSArray は添字ではアクセスできない。
JavaScript の配列でないからか、当然 forEach も length も使えない。
UTF8String に変換した後の文字列は添字可能、色々戸惑う。
バインドしているのではなく明確に型を分けているということみたい。

そんなこんなで。
Mac では JavaScript だけでやっていこうと思っていたけどコリャ無理だ。
Objective-C の勉強も始めますか、Fedora では使わないと思うけど。

Mac JavaScript 日本語

osascript にて文字列のファイル保存。
いくら探しても皆アルファベットでしか保存していない。
理由はコレ。

#!/usr/bin/osascript

ObjC.import("Cocoa");

var jstr = "日本語が化ける";
var fname = "/Users/sasakima-nao/ng.txt";

app = Application.currentApplication();
app.includeStandardAdditions = true;

var refno = app.openForAccess(Path(fname), {
    writePermission: true
});
app.write(jstr, {
    to: refno
});
app.closeAccess(refno);

var cmd = "cat " + fname;
app.doShellScript(cmd);

cat_xxx

doShellScript の cat では普通に日本語処理できている。
けど普通に cat すると見事に文字化けするんだなぁこれが。
TextEdit.app で開くと問題無し、だけど別名保存しようとしてみよう。

textedit_jp

日本語(Mac OS) って何だよ?

MacJapanese – Wikipedia

コレらしい、osascript の内部文字列は古い Mac のままなのか…
AppleScript 自体は昔からあるのでそのまんま拡張しただけと憶測。
結果文字列をそのまま保存すると内部文字列のままで出力されると。

Mac 内製アプリは対応しているけど今の $LANG は UTF-8 だよ。
NSString は UTF-16 みたい、Mac も Windows と変わらないカオスだった。
Linux が一番進んでいるって笑えないYO!

とりあえず iconv で変換すればいいのかな?

UTF-8-MAC なんていう文字コードはありません | ものかの

cat ng.txt | iconv -f UTF8-MAC -t UTF8

とやってもエラー、UTF-16 から変換にすると中国語?
手段はあるだろうけどブン投げる、調べるだけ時間の無駄だ。

だって UTF-8 で出力しないと意味無いってば!

#!/usr/bin/osascript

ObjC.import("Cocoa");

var jstr = "コレなら日本語 OK です\n";
var fname = "/Users/sasakima-nao/ok.txt";

var nsstr = $.NSString.alloc.initWithString(jstr);

var data = nsstr.dataUsingEncoding($.NSUTF8StringEncoding);
var res = data.writeToFileAtomically(fname, true);
if (res) {
    app = Application.currentApplication();
    app.includeStandardAdditions = true;
    var cmd = "cat " + fname;
    app.doShellScript(cmd);
}

これでなんとかなった。
NSString に変換して UTF-8 で NSData に変換してバイナリで保存。

cat.ok

Apple が作っている言語なのに何だよこのアホ臭さ。
結論、コンソールアプリはサードパーティの言語でやったほうがいい。

でもこういうことに苦戦するのがプログラミングの楽しみでもあって。
Linux に移行した直後に pygtk と格闘していた頃も楽しかった。

Mac JavaScript getenv

Linux 屋が Mac を使うと環境変数が少ないなぁと感じる。

env

そのせいか osascript で環境変数を得る方法がなかなか見つからなかった。
いくら検索してもパスを通すことばかり、Windows と変わらないじゃん。
三時間くらい探し続けてやっと見つけた。

CotEditor :: ひまつぶし雑記帖

鳶嶋工房 / AppleScript / JavaScript for Automation (JXA)

osascript って stdlib のインクルードも可能なのか。
なら stdio もイケるかも、よしやってみよう。

#!/usr/bin/osascript

ObjC.import("stdlib");
ObjC.import("stdio");

var user = $.getenv("USER");
//console.log("ユーザー名は " + user + " です");
// 戻り値が出力されるので変数に入れている
// printf って転送バイト数が戻るとは知らなかった...
// 自動改行されるので \n を省いています
var dev_null = $.printf("ユーザー名は %s です", user);

/* //ShellScript から得るという手段もある
app = Application.currentApplication();
app.includeStandardAdditions = true;
var path = app.doShellScript("echo $LANG");
console.log("$LANG は " + path + " です");
*/

getenv

なんだよ、glibc の関数が普通に使えるじゃないか。
しかし今まで何気に使っていた printf にこんな罠が。

ただ printf と console.log は混在させないほうがいい。
上記下側のコメントアウトを外してみよう。

output_pointer

出力が上下で入れ替わってしまった、ように見えますが。
単に printf と console.log で出力ポインタ管理が違う。
つまり console.log の出力は行先頭のままになる。
結果、最初の出力が console.log の出力に押し出されてこうなる。

#!/usr/bin/osascript

ObjC.import("string");

var nae = "優木苗";
console.log(nae.length); //=>3
console.log($.strlen(nae)); //=>9

おぉ日本語のバイト数も C 標準関数を使えば得られる。
Gjs で GLib 関数がフルに使えるのとほぼ同じことができるのね。
Mac で JavaScript も想像していたより便利そうです。

Mac Script (No Terminal.app)

Mac で AppleScript/JavaScript を端末起動無しで使う手段があった。

OSXのアプリケーションをJavaScriptで作る – Qiita

Mac には osacompile なんてスクリプトコンパイラがあったのか。
これで Mac でもスクリプトを使う時にターミナルを開かずに使えるぞ!

っっって、それじゃ意味無いジャン。

スクリプト言語はコンパイルせずにスパッと使えるのがメリットなんだから。
つかコンパイルするなら Swift とかで作ったほうが絶対に楽だし。

世の中にはそうしたい奇妙な人が結構いることは置いておいて。
特に IronPython でコンパイルしたい人の多さにドン引きDESU。

うーん、コンパイルせずにターミナルを開かない方法は…
あ、Automator という手があった。

Automatorで簡単にコマンド実行アプリを作る|MacFan

この程度ならシェルスクリプトのほうが圧倒的に簡単だと思うんですけど…
それはいいとして。

この手段で端末を開かずに bash 等のシェルが使えるようだ。
本当に上手くいくのかな?
JavaScript でウインドウを作って試してみよう。

いや、筆者はまだ Cocoa がよく解っていない。
なので上のリンク先にあるウインドウを作るスクリプトをコピペ。

app_create

と Bash から osascript にスクリプトのフルパスを与えて。
JavaScript でも -l オプションは必要無かったのね。
/Applications 内に保存して Finder から W クリックしてみる。

app_exec

よしスクリプトのまま端末起動無しで実行できた。
しっかり Dock にも表示される、アイコンは自前で入れればイケそう。

実行パーミッションを付ける必要もないしメンテも簡単そう。
シェルで起動しているだけだから Python でも何でもイケるな。
何より書き換えしてもコンパイルのやりなおしをする必要が無い。

いいことづくめに感じるけど、ただただ面倒臭い!
Linux と PyGObject コンビがドンダケ神がかっているか思い知るだけだった。