月別アーカイブ: 2017年3月

JXA NSWindow

今回は JXA でウインドウを作ってみる。

実はウチの PyGObject Tips ページのアクセス数で解るんだけどさ。
ウインドウを作るのページだけブッチギリで多いのよ、初心者ってそんなもんだ。
なんだかなぁ、プログラミングが面白いのはその先からだと思うんですけど。
ということで画像も表示してみる。

検索すると色々な実装があるけど結果は全部同じだね。
それなら簡潔で理解が早い人が多いっぽい実装を選んでみよう。

でも気に入らないのは大半の人がウインドウを閉じると終了するコードだ。
おい macOS だぞ、メニューバーに command+Q は必須だろ?
それと無意味な即時実行多すぎ、多分よく解っていないんだろうけど。

NSApp.servicesMenu in JXA ? GitHub

なんだよ、command+Q メニューはこんなにアッサリ実装できるんかい。
まさかこんなところでバックコーテーションを使うとは。
alloc.init だけなら new メソッドでいいみたい、ふむふむ。

しかし一回しか使わない関数なら無名関数の即時実行でいいのに。
即時実行ってそういう場合に使うと思うんだが。
ということで、こんなサンプルコードになりました。

#!/usr/bin/osascript

ObjC.import("Cocoa");

const imgePath = $("/Users/sasakima-nao/Pictures/[シクシクおよよ]三嶋ゆらら(SSR).jpg");

/**
 * Contents
 */
let image = $.NSImage.alloc.initWithContentsOfFile(imgePath);
if (image.isNil()) {
    console.log("Image Not Found.");
}
let imageView = $.NSImageView.alloc.initWithFrame(
    $.NSMakeRect(0, 0, 320, 400)
);
imageView.setImageScaling($.NSScaleToFit);
imageView.setImage(image);

/**
 * Window
 */
let window = $.NSWindow.alloc.initWithContentRectStyleMaskBackingDefer(
    $.NSMakeRect(0, 0, 320, 400),
    $.NSTitledWindowMask
    | $.NSClosableWindowMask
    | $.NSMiniaturizableWindowMask,
    //| $.NSResizableWindowMask,
    $.NSBackingStoreBuffered,
    false
);
window.title = $("[シクシクおよよ]三嶋ゆらら(SSR)");
window.center;
window.orderFrontRegardless;
window.contentView.addSubview(imageView);

/**
 * Application
 */
let app = $.NSApplication.sharedApplication;
app.setActivationPolicy($.NSApplicationActivationPolicyRegular);
app.mainMenu = function() {
    
    function newMenu(title, action, key) {
       return $.NSMenuItem.alloc.initWithTitleActionKeyEquivalent(title, action, key);
    }
    
    const appName = "Test Window";
    
    const mainMenu = $.NSMenu.new;
    const itemApp  = $.NSMenuItem.new;
    const menuApp  = $.NSMenu.new;
    itemApp.submenu  = menuApp;
    mainMenu.addItem(itemApp);
    menuApp.addItem(newMenu(`Quit ${appName}`, 'terminate:', 'q') );

    return mainMenu;
}();
app.run;

やばい、ゆららちゃんがこんなにカワイイとは!
つい炭酸全部使ってフルマカロン取っ、、、、、いやそれはどうでもよくて。

macOS アプリって Application と Window に何も関連性が無いんだね。
あぁだから macOS では Window を全部閉じてもアプリは終了しないのか。

GTK+, WPF, VCL 等は全部 Application class が Window を管理している。
で、管理する Window が無くなったら Application が終了する、という流れ。
mac は本当に独特なんだなと。

しかしメソッドに括弧が無いのは相変わらず慣れない。
app.run にすら不要って意味ワカンネ!

run JXA in Visual Studio Code

Visual Studio Code (以下 Code)で新たな発見。

他のエディタと同じファイルを開いて他側にて上書き保存。
すると即座に Code は全自動で読み直ししてくれる、凄い!
更に開いているファイルを削除すると全自動でタブを閉じてくれる、凄い!

正直迷惑な場合が多いのですけど…

筆者は macOS で日本語が入力できない Gedit の代用で使っている。
alt(option)+上下矢印キーで行入れ替え
fn+左矢印キー(Home) でインデントの先頭へ移動
shift+tab で選択していなくてもインデント戻し
が可能なエディタをこの2つしか知らないのでしかたがない。

ウザいだけのインテリセンスを無効にして騙し騙し使っていたり。
問題は F5 デバックだ。
そもそも F5 にしている理由は Visual Studio に合わせたのですし。
Gedit で Python スクリプトを debug – L’Isola di Niente

Code で F5 を叩くと、なんで node.js 専用なんだよ!
筆者は JXA しかやるつもりは無い、代用手段は無いのか?

特集:Visual Studio Code早分かりガイド:Visual Studio Codeの使い勝手をよくするツール (1/5) – @IT

あるみたい。
ということで F5 に割り付けしてみよう!

run task をコマンドパレットに打ち込んでも出ない、あれ?
って「タスク」と日本語で打ち込まないといけなくなったようで。
shift+command+B は普通に使えるようだ、って覚えにくいよ。

tasks.json はディレクトリ毎に作られるようで。
とにかく以下のように書き換える。

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "0.1.0",
    "command": "osascript",
    "isShellCommand": true,
    "args": ["${file}"],
    "showOutput": "always"
}

${file} 変数はココで使えるかどうか見つからないけど実験をかねて。
んで、キーボードショートカットの f5 を上書き。

// 既定値を上書きするには、このファイル内にキー バインドを挿入します
[
    {
        "key": "f5",
        "command": "workbench.action.tasks.build"
    }
]

ここまでやって f5 を叩いてみる。

おぉコレは!
と思ったけどこの機能はファイル単体で開いた時では使えないのね。
使うには毎回 [フォルダを開く] をやらなきゃいけないみたい。
うーん…

bash macOS

bash は大文字と小文字を厳格に区別する。
しかし macOS の bash は echo, pwd 等の大小文字を区別しない。
ところが if や変数名は普通に区別することに今頃気がつく。

shopt あたりにそうなるオプションが…無かった。
$- の値も Fedora と同じ himBH だった。
じゃあ何故大文字でも echo 等が使えるのだ?

解ってしまえば単純な話で。
組み込みコマンドではなく /bin/echo が使われていただけ。
ファイル名の大文字小文字を区別しないからこんな変なことになるんじゃ!

bash indirection

${!prefix*}
という記述で bash はその接頭子の変数名をブレース展開してくれるらしい。
ビックリマークは間接参照という意味らしい。

さっそくテストコードを書いてみたら見事にハマった!

#!/bin/sh

GF_top='心美 文緒 くおえ'
GF_loli='苗 睦 桃子'

echo ${!GF_*}

for gf in ${!GF_*}; do
    #for s in $gf; do
    for s in ${!gf}; do
        echo $s
    done
done

$gf という記述ではこの場合変数展開できない。
変数名で出力されるので ${${gf}} とかワケワカなことしてみたり。

よーく考えたら当然だった。
$gf なんて変数は定義していないんですもの。
どんな言語でもこんなことはできないよ。

なのでココでも間接参照で実際の変数を見つけてもらう必要がある。
シェルスクリプトって上記ができるとつい勘違いするよね、筆者だけ?

/usr/bin/js

Fedora のデフォルトでは gjs, jjs の他に js というコマンドがある。
当然 JavaScript 関連だと思うんだけど、コレって何?

どう考えても gjs, jjs 共に関係無さそうなんだけーが。
もしかして Webkit の絡みで JavaScriptCore だったり。

JXA and JavaScriptCore stdin | PaePoi

ビンゴで自分で驚いた。
経験値って恐ろしい、けれど微妙に違うのね。

間違えていたので以下修正

どうやら mozjs というものらしい。
JavaScriptCore は以下に別途でありました。

/usr/libexec/webkit2gtk-4.0/jsc

JSC ? WebKit
ビルトイン関数はまったく同じだった。
ただ mozjs の readline は UNICODE で処理しているようだ。
jsc は macOS 同様に変換して取り込む必要がある。

何にせよコイツだけじゃ何もできないんだけどね。