JXA」タグアーカイブ

M1 Mac JXA and PyObjC

会社の都合で休日出勤は無しなので M1 Air をしっかり試す。
たしかパワーは 2019 Air の五倍なので筆者の 2018 からだと八倍くらいか。
ログイン画面まで 15 秒、パスワードを打ち込みプラス 15 秒でもう使える。
他に Web でベタ褒めされている件、あれらは全部本当だった。
こんなの筆者の知っている Macbook Air じゃない、怪物にも程がある。

とりあえず再構築、Atom を公式サイトから入れよう。
起動しようとすると Rosetta2 をインストールしますか?とアラートが。
インストールを選ぶと一瞬で入ったから内部で有効化しただけだと思うけど。
ぶっちゃけ来年くらいまでは全員が入れると思う。

Atom を Gedit のように使う – Paepoi

再構築完了、書いてて良かった自前カスタムのすべて。
早速 JXA を試そう、ES2020 は対応されているか。
?? 演算子と BigInt と globalThis をまとめてテスト。

#!/usr/bin/osascript

const p = globalThis.print ?? console?.log;
p(12341234123412341234n *2n);

atom_run

動くじゃないの。

GNOME 3.38 Gjs | Paepoi Blog
import 関数は使えない。
Promise も動いた、ただ筆者には便利さが解らない。
matchAll も動く、Gjs と同じく詳細は出力されないけど。

だいたい Gjs と同じって感じ。
ただし、NSMakeRect のバグはそのまんまだ、やっぱりやる気無いのね。

しかしマジで Python2 がデフォルトで入っているのがなんとも。
PHP は 7.3.22 か、さくらインターネットでさえ 7.4.10 なのに。
perl と ruby はどうでもいい。

端末で python3 と打ち込むと CommandLineTools のダイアログ。
インストールすると Python3 が使える、3.8.2 だ。
普通に使えるけど、PyObjC が pip3 でインストールできない。

Python Release Python 3.9.1 | Python.org

macOS 64-bit universal2 installer
というものが公式にあった、これならイケるかな。
CommandLineTools を先に入れないと 3.8 に上書きされるので注意。
インストーラに従うだけで 3.9 にアップグレードできる。
んで、pip3 のアップグレードを行う必要があった。

# pip upgrade
pip3 install --upgrade pip
# install
pip3 install -U pyobjc

PyObjC Tips – Paepoi

PyObjC

PyObjC もコレで問題なく動くじゃないの。
少し面倒だったけど混迷期だからしかたがないね。

JXA readline

現在本サイトの JXA Tips を書き換えしている。
以下の Objective-C Bridge の所を見ていたんだけーが。

OS?X 10.10 Release Notes

あれ、readline が import できるみたい。

GNU Readline – Wikipedia

stdio や unistd のように C と同じように使えるのかな。

#!/usr/bin/osascript

ObjC.import('readline');

console.log('May I ask your name?');
let s = $.readline('>> ');
console.log(`Hello ${s} san`);

jxa_readline

JXA の stdin ってこんなに簡単だったんだ!
世界中探しても見つからなかったのにこんちくしょう。

CRLF

何を今頃だけど JavaScript の replace について。

String.prototype.replace() – JavaScript | MDN

第一引数を正規表現にすればすべてのマッチした箇所を置換できるのか。
最初に一致した箇所だけだとずっと勘違いしていた筆者であった。

JXA: doShellScript Line feed code | Paepoi Blog

これを試しに書き換えしてみよう。

#!/usr/bin/osascript

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

res = app.doShellScript('ls -l');
console.log(res.replace(/\r/g, '\n'));

いけた。

ついでに。
よく考えたらコマンドの中で tr を使って変換すりゃいいじゃん。
と思ってやってみたら上手くいかなかった。

#!/usr/bin/osascript

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

// no...
//res = app.doShellScript('ls -l | tr "\r" "\n"');

// test
res = app.doShellScript('ls -l | tr "\n" "|"');
console.log(res);

となる。

つまりコマンド実行の時点では改行コードは LF のまま。
doShellScript が値を戻す時に CR へ変換しているようです。
LF のまま戻すオプションって無いのかな?

lf

#!/usr/bin/osascript

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

res = app.doShellScript('ls -l', {alteringLineEndings:false});
console.log(res);

あった、今後はコレで。

ついでに、doShellScript は bash の POSIX 互換モードです。
zsh やフル状態の bash ではないので注意、macOS って本当に色々面倒臭い。
プログラミングするならやっぱり Linux だよ、某サル専用を除く。

関係ないけど Macbook Air 2020 が出たね、かなり良さげ。
でも筆者はこんな使い方ばかりだから 2018 モデルで何の不満も無いのよね。
ペチペチキーボードにもすっかり慣れてしまったし、うるさいけど。
さて 10.15.4 にアップデートするか。

macOS Get UTI

Apple 関連で開発をしていると UTI を調べる必要がある場合が多々ある。

Uniform Type Identifier – Wikipedia

Uniform Type Identifier Concepts

検索をしていたら素敵なページを見つけた。

Mac や iOS でファイルの種類を表す識別子 Uniform Type Identifiers を拡張子から調べる(Swiftで1行で出来る) – niwatakoのはてなブログ

てゆーか JXA でも PyObjC でもできる。
しかし困ったことに JXA では CFString が NSString にキャストできない。

objective c – JXA: Accessing CFString constants from CoreServices – Stack Overflow

上記を見つけてようやく解決。
console.log って C 言語の char[] を出力できる、初めて知った。
UTF16LE に変換は不要、CJK 文字列でも問題ないようです。

#!/usr/bin/osascript -l JavaScript

let jp = $('スズキ GSX250R').UTF8String;
console.log(jp);
//=> スズキ GSX250R

// ex: ft=js.jxa

ということで JXA にて簡単に調べるコマンドを作ってみる。

#!/usr/bin/osascript -l JavaScript

ObjC.import('CoreServices');

function run(argv) {
    for (let ext of argv) {
        let uti = $.UTTypeCreatePreferredIdentifierForTag(
            $.kUTTagClassFilenameExtension, $(ext), null);
        let s = $.CFStringGetCStringPtr(uti, 0);
        console.log(`${ext}: ${s}`);
    }
}

// ex: ft=js.jxa

getuti.js

せっかくなので基底タイプも調べたいぞ。
JXA で得る方法が解らなかったので PyObjC で書いてみる。
PyObjC は CFDictionary や CFString も Python の型と等価なので超簡単。
他の言語を使うのが馬鹿馬鹿しくなってしまうので注意が必要。

#!/usr/bin/env python3

import sys, CoreServices

for ext in sys.argv[1:]:
    uti = CoreServices.UTTypeCreatePreferredIdentifierForTag(
        CoreServices.kUTTagClassFilenameExtension, ext, None)
    arr = CoreServices.UTTypeCopyDeclaration(uti)['UTTypeConformsTo']
    con = ','.join(arr)
    print(f'{ext}: {uti} [{con}]')

# ex: ft=py

@PyObjC

getuti という拡張子の無い名前で +x のパーミッションを付けパスの通った場所へ。

getuti

JXA でやりたかったけどまだまだ修行が足りない。

注意: macOS 13 Ventura からは上記が使えません。
macOS: Get UTI (Ventura) | Paepoi Blog

Catalina Atom JavaScript

おいおい、Atom の Script パッケージって…

Script はシバンを書かなければパスを通した node.js で実行するようです。
シバンを osascript に指定してもパラメーターは node.js 用のまま。
どういうことだってばよ。

右下にある言語の所をクリックし

JavaScript for Automamation (jxa)

を選択すれば osascript 用のパラメーターになるようです。

こんなのを毎回やるのなんて面倒臭いぞ。
ということで vim-modeline を使うことにする。

#!/usr/bin/osascript

console.log('Hello');

// vim:set ft=js.jxa

vim 屋は最終行に書いている場合が多いので合わせてみた。
Atom のみならこの表記でいい、本家 vim を併用している人は困るかも。
書き込んだ後に開き直すか option+control+V を押す。

問題なく JXA で起動できるようになります。
普通にシバンどおりに実行してくれたほうが嬉しいのに。

ところで node.js なんだけど。

普通にダウンロードしテキトーに置いた奴は起動できなくなっていた。
上記は以前試した graalvm に入っていた奴なんだけどね。
Gatekeeper がどんどん厳しくなるなぁ。
正式な手段でインストールしないと全部弾かれるようになったみたい。

macOS Catalinaでnode.jsをインストール – Qiita
node.jsのversionを管理するためにnodebrewを利用する – Qiita

curl -L git.io/nodebrew | perl - setup

を実行すると ~/.nodebrew が作られる。
筆者は zsh に変更したので ~/.zshrc にパスを書き込む。
しかし mac 屋は何故ドットコマンドではなく source を使うのか?

. ~/.zshrc

Node.js

コレを書いた時点の LTS は 10.16.3 である。

# ~/.nodebrew/src にバイナリでダウンロード
# ~/.nodebrew/node に展開
nodebrew install-binary v10.16.3

# ~/.nodebrew/current のリンク先を指定先に変更する
# ~/.nodebrew/current/bin に nodebrew 自体のリンクを貼る
nodebrew use v10.16.3

全部 $HOME 以下に展開されるけど問題なく使えるようになった。
Gatekeeper の仕組みがイマイチわからないな。