月別アーカイブ: 2018年2月

unzip escape

comipoli を gjs 化するので python3 の zipfile が使えない。
ということで unzip コマンドを使う方法に切り替えるのだが
展開する内部ファイル名にブラケット [, ] があると展開できないと気が付いた。

検索するとアスタリスクが駄目なことは皆気がついているようだ、他にもあるかな?
file-roller の GPL ソースを見るのが一番速い。

file-roller/fr-command-zip.c at master ? GNOME/file-roller ? GitHub

[]*?!^-\

こんなにあった、てか記号全部ではないのね。
駄目文字の前にバックスラッシュを付けるだけだし変換は簡単だね。

var ComipoliArchive = class ComipoliArchive {
    // etc...
    _zipEscape(str) {
        const ESCAPE = "[]*?!^-\\";
        let res = "";
        for (let s of str) {
            if (ESCAPE.includes(s)) res += "\\";
            res += s;
        }
        return res;
    }
    getItem(num) {
        let cmdArray = null;
        let pixbuf = null;
        switch (this.status) {
        case 1:
            cmdArray = ["unrar", "p", "-inul", "-@", "--", this.path, this.namelist[num]];
            break;
        case 2:
            cmdArray = ["7za", "x", "-so", this.path, this.namelist[num]];
            break;
        default:
            //cmdArray = ["unzip", "-pj", this.path, this.namelist[num]];
            cmdArray = ["unzip", "-pj", this.path, this._zipEscape(this.namelist[num])];
        }
        let sp = Gio.Subprocess.new(cmdArray, Gio.SubprocessFlags.STDOUT_PIPE);
        let stream = sp.get_stdout_pipe();
        try {
            pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, null);
        }
        catch(e) {
            print("Error: " + this.namelist[num] + "\n" + e);
        }
        stream.close(null);
        return pixbuf;
    }
}

展開できた。

しかし cairo 描写に書き換えたら 3D で動く毎に draw シグナルが…
これでは clutter_actor_save_easing_state が使えないや。

yield @ Python3 and JavaScript

我が comipoli はどうせ cairo に書き換えるなら Gjs 化してしまおう。
ということで以前 ClutterImage 作成が遅過ぎでお蔵入りしたソースを引っ張りだした。
ES6 仕様に書き換えをしていて yield でハマったので覚書。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib

class Dlg(Gtk.Dialog):
    def __init__(self):
        Gtk.Dialog.__init__(self, transient_for=None, title="Comipoli Thumbnail")
        self.show_all()
        # idle
        self.iter = self.iter_func()
        GLib.idle_add(self.iter_idle)

    def iter_idle(self):
        try:
            n = next(self.iter)
            print(n)
            return True
        except Exception as e:
            return False

    def iter_func(self):
        for num in range(100):
            yield num

dlg = Dlg()
dlg.run()
dlg.destroy()

PyGObject

#!/usr/bin/gjs

const GObject = imports.gi.GObject;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;

var Dlg = GObject.registerClass({
    GTypeName: "Dlg"
}, class Dlg extends Gtk.Dialog {
    _init() {
        super._init({
            transient_for: null,
            title: "Comipoli Thumbnail"
        });
        this.show_all();
        // idle
        this.iter = this.iter_func();
        GLib.idle_add(GLib.PRIORITY_LOW, ()=> {
            let r = this.iter.next();
            if (r.done) return false;
            print(r.value);
            return true;
        });
    }
    * iter_func() {
        for (let i=0; i<100; i++) {
            yield i;
        }
    }
});
Gtk.init(null);
let dlg = new Dlg();
dlg.run();
dlg.destroy();

Gjs

g_idle_add の引数が違うことは置いておいて。
g_idle_add は何も処理を行っていない時に与えられた関数を実行し続ける関数。
false を戻さないかぎり動き続ける。

Python は例外で判別、JavaScript は next メソッドの戻り値で判別。
yield, next の使い方はまったく同じなので混乱してもーたがね。

検索すると個別で next() を呼んでいる人ばかりで困ったよ。
どう考えても yield でそんな使い方はしないと思うんですけど。
複数ファイル処理で一つ読み終わったらとっとと表示みたいな場合が主だよね。

あと JavaScript のジェネレーター関数はアスタリスクが必要。
無名関数にする手段は無いっぽい、JavaScript を筆者が使うようになった切っ掛けなのに。
でも Python には無名関数はいらないな、そんなの Python じゃない。
適材適所ってことですよ、何でもアリはコードを読み辛くするだけだ。