Posts
Jetpackで何か作ってみたかったので作ってみた。
OperaでATOK 2007 for Windowsの電子辞典を使うためのツールが必要。
ステータスバーにATOKのアイコンが出ます。
テキストを選択した状態で、アイコンをクリックすると電子辞典の検索を行います。
本当はコンテキストメニューに登録して呼び出すのがやりたかったんだけど、
Jetpackでやる方法がわからなかったので、この形にしました。
(function() {
var cmd = 'c:\\path\\to\\GetTextOperaLClick.exe';
var convert = function(s, charset) {
var ccls = "@mozilla.org/intl/scriptableunicodeconverter";
var cif = Components.interfaces.nsIScriptableUnicodeConverter;
var c = Components.classes[ccls].getService(cif);
c.charset = charset;
return c.ConvertFromUnicode(s);
}
var lookup = function(s) {
var fcls = "@mozilla.org/file/local;1";
var fif = Components.interfaces.nsILocalFile;
var pcls = "@mozilla.org/process/util;1";
var pif = Components.interfaces.nsIProcess;
var file = Components.classes[fcls].createInstance(fif);
file.initWithPath(cmd);
var process = Components.classes[pcls].createInstance(pif);
process.init(file);
var args = [convert(s, "shift_jis")];
process.run(false, args, args.length);
}
jetpack.statusBar.append({
html: '<img id="icon_img" src="http://www.atok.com/favicon.ico />',
width: 30,
onReady: function(doc) {
$('#icon_img', doc).css({
cursor: "pointer",
});
$(doc).click(function() {
var w = jetpack.tabs.focused.contentDocument.getSelection();
if (w.length) {
lookup(w);
}
});
}
});
})();
選択するだけで検索する版(使いにくい)
アイコンをクリックすると、機能のon/offができます。
無効(初期)状態では、アイコンが半透明になっています。
有効になっているときは、テキストを選択してマウスのボタンを離すと電子辞典の検索が動きます。
(クリックイベントが発生したときに、選択されているテキストの長さで判断してます)
(function() {
var cmd = 'c:\\path\\to\\GetTextOperaLClick.exe';
var enabled = false;
var convert = function(s, charset) {
var ccls = "@mozilla.org/intl/scriptableunicodeconverter";
var cif = Components.interfaces.nsIScriptableUnicodeConverter;
var c = Components.classes[ccls].getService(cif);
c.charset = charset;
return c.ConvertFromUnicode(s);
}
var lookup = function(s) {
var fcls = "@mozilla.org/file/local;1";
var fif = Components.interfaces.nsILocalFile;
var pcls = "@mozilla.org/process/util;1";
var pif = Components.interfaces.nsIProcess;
var file = Components.classes[fcls].createInstance(fif);
file.initWithPath(cmd);
var process = Components.classes[pcls].createInstance(pif);
process.init(file);
var args = [convert(s, "shift_jis")];
process.run(false, args, args.length);
}
jetpack.statusBar.append({
html: '<img id="icon_img" src="http://www.atok.com/favicon.ico />',
width: 30,
onReady: function(doc) {
$('#icon_img', doc).css({
cursor: "pointer",
opacity: 0.4
});
$(doc).click(function() {
var elem = $('#icon_img', doc);
var a;
if (enabled = !enabled) {
a = 1;
$(jetpack.tabs.focused.contentDocument).click(function() {
var w = jetpack.tabs.focused.contentDocument.getSelection();
if (w.length) {
lookup(w);
}
});
} else {
a = 0.4;
$(jetpack.tabs.focused.contentDocument).unbind('click');
}
elem.css({opacity: a});
});
}
});
})();
前作ったやつは、スタイル出力、HTML出力、スタイル埋め込みという手順を踏む必要があって面倒なので、pygmentsのAPIを使って一発で処理するようにしてみた。
前のは出力されたcssとHTMLを処理するのでstyle, lexerなんかは好きにすればよかったけど、
今回は1passなのでそこら辺の指定をできるようにしてみた。
from pygments import highlight
from pygments.lexers import get_lexer_by_name, get_lexer_for_filename
from pygments.formatters import get_formatter_by_name
from xml.etree.ElementTree import ElementTree, XML
import cssutils
from cssutils.css import CSSRule
from sys import stdout
from optparse import OptionParser
def write(filename, style_name='colorful', formatter_name='html', lexer_name=None, out=stdout):
fmtter = get_formatter_by_name(formatter_name, style=style_name)
if lexer_name:
lexer = get_lexer_by_name(lexer_name)
else:
lexer = get_lexer_for_filename(filename)
css = cssutils.parseString(fmtter.get_style_defs())
rules = dict([(x.selectorText, x.style.cssText.replace('\n', '')) for x in css.cssRules if x.type == CSSRule.STYLE_RULE])
tree = ElementTree(XML(highlight(open(filename).read(), lexer, fmtter)))
for elem in tree.getiterator():
c = elem.get('class', None)
if c:
style = rules.get('.'+c, None)
if style:
elem.attrib['style'] = style
tree.write(out)
if __name__ == '__main__':
optparser = OptionParser(usage=u'usage: %prog [options] file')
optparser.add_option('-S', '--style', dest='style', help='style', default='colorful')
optparser.add_option('-f', '--formatter', dest='formatter', help='formatter', default='html')
optparser.add_option('-L', '--lexer', dest='lexer', help='lexer')
options, args = optparser.parse_args()
if len(args) == 1:
write(args[0], options.style, options.formatter, options.lexer, stdout)
else:
print '** no input file specified **'
optparser.print_help()
外部電源の外付けハードディスクだと、つなぐのが面倒でバックアップをサボりがちだったので、
バスパワーで動くUSB接続のハードディスクをさがしていた。
ちょうど、来月分の生協のチラシにHDPS-U500がのっていたので、これでいいかな?と思っていたら、
土曜日に寄った川崎のヨドバシで同じものがポイント20%還元になってた(ポイント分引けば9000円切ってる)ので買ってしまった。
8G/残りでパーティションを分けて、8Gの方からTrueImage(Home 10)を起動できるようにした。
手順は簡単で、TrueImage が起動する USB-HDD ( USB メモリ ) の作り方をそのままやればできた。
基本的にWindows上でバックアップするけど、復旧のこと考えるとこうしておいた方が安心。
(私の環境は1スピンドルでUSBが3ポート。USB光学ドライブはUSBを2ポートふさいでしまうので、HDDをつなぐと全部埋まる)
ここでソース張っても色とかつけるのが大変なので、pygmentsのhtml出力とcssを結合するスクリプトを書いてみた。
embedstyle.py
import sys
from xml.etree.ElementTree import ElementTree
import cssutils
from cssutils.css import CSSRule
css = cssutils.parseFile(sys.argv[2])
rules = dict([(x.selectorText, x.style.cssText.replace('\n', '')) for x in css.cssRules if x.type == CSSRule.STYLE_RULE])
tree = ElementTree(file=open(sys.argv[1]))
for elem in tree.getiterator():
c = elem.get('class', None)
if c:
style = rules.get('.'+c, None)
if style:
elem.attrib['style'] = style
tree.write(sys.stdout)
使用例
スタイル生成→HTML出力→結合
pygmentize -f html -S colorful > test.csspygmentize -o embedstyle.html embedstyle.py
python embedstyle.py pkglist.html test.css > out.html
これで出力したのがこのページのコード
ディスクの空きがちょっと減ってきたので、サイズが大きいパッケージを知りたくて作ってみた。
python-aptとprettytable使ってます。
#!/usr/bin/python
import apt
from prettytable import PrettyTable
pt = PrettyTable(["package", "version", "size"])
pt.set_field_align("package", "l")
pt.set_field_align("version", "r")
pt.set_field_align("size", "r")
pt.set_padding_width(1)
SizeToStr = apt.SizeToStr
for v in sorted([x.installed for x in apt.cache.Cache() if x.isInstalled], key=lambda v: v.installed_size):
pt.add_row((v.package.name, v.version, SizeToStr(v.installed_size)))
print pt
出力
+----------------------------------------------------------+------------------------------------------+-------+
| package | version | size |
+----------------------------------------------------------+------------------------------------------+-------+
| adobe-certs | 1.0.8210 | 0 |
| adobeair1.0 | 1.5.1.8210 | 0 |
| tweetdeckfast.f9107117265db7542c1a806c8db837742ce14c21.1 | 0.22 | 0 |
| gnuplot | 4.2.5-2 | 20.5k |
| uim | 1:1.5.3-1 | 20.5k |
(省略)
| texlive-latex-extra-doc | 2007.dfsg.17-2ubuntu1 | 110M |
| openoffice.org-core | 1:3.1.0-3ubuntu2 | 113M |
| llvm-dev | 2.5+svn20090504-0ubuntu1 | 117M |
| ghc6 | 6.10.3-2ubuntu1 | 148M |
+----------------------------------------------------------+------------------------------------------+-------+
sys.stderrにメッセージを出力しているモジュールがあって、それを書き換えずに何とかしたいので考えてみた。
とりあえずうまくいったけど、いいのかわからない。
(追記
すっかり忘れてたけど、sys.stderrをほかの変数で参照してたらだめだった。当たり前なんだけど…
別モジュールで、from sys import stderrなら
モジュール名.stderrを書き換えればOK)
import sys
import logging
from StringIO import StringIO
class redir(object):
def __init__(self, f):
self.f = f
self.eol = True
def write(self, buf):
if buf == '\n':
if self.eol:
self.f('')
else:
self.eol = True
else:
self.eol = False
self.f(buf)
print >>sys.stderr, "hoge"
logging.basicConfig(filename='hoge.log', level=logging.DEBUG)
sys.stderr = redir(logging.error)
print >>sys.stderr, "hoge1"
print >>sys.stderr
print >>sys.stderr, "hoge2"
これで、最初の出力(hoge)はstderrに、以降の出力(hoge1,改行のみ,hoge2)はhoge.logに出力される。
調べ方メモ
6.6. The print statementを見て、出力先のオブジェクトにwriteが必要なことと、(必要なときは)最後に'\n'がくることはわかった。
writeに渡されるバッファに最後の改行が含まれているのか、改行だけ別に呼ばれるのか気になるので調べてみた。
適当な関数を作って、disで調べた。
>>> import dis
>>> def f():
... print >>None, None,
...
>>> def fln():
... print >>None, None
...
>>> def fnl():
... print >>None
...
>>> dis.dis(f)
2 0 LOAD_CONST 0 (None)
3 DUP_TOP
4 LOAD_CONST 0 (None)
7 ROT_TWO
8 PRINT_ITEM_TO
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> dis.dis(fln)
2 0 LOAD_CONST 0 (None)
3 DUP_TOP
4 LOAD_CONST 0 (None)
7 ROT_TWO
8 PRINT_ITEM_TO
9 PRINT_NEWLINE_TO
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> dis(fnl)
2 0 LOAD_CONST 0 (None)
3 PRINT_NEWLINE_TO
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
>>>
たぶん、PRINT_ITEM_TOがデータの出力で、PRINT_NEWLINE_TOは改行であろうことはわかる。
改行付きのprintがPRINT_ITEM_TOと、PRINT_NEWLINE_TOと二つに分かれているので、2回に分けてwriteが呼ばれそうなこともわかる。
ともかく、PRINT_ITEM_TOとPRINT_NEWLINE_TOは間違いなくキーワードなので調べると、PRINT_ITEM_TOとPRINT_NEWLINE_TOは拡張版print statementで使われるのがわかる。それぞれ出力を行う命令なので、writeが二度呼ばれるものとして扱ってよさそう。
素直にそのままloggingすると、最後の改行までログに残ってしまうので邪魔。ただ、単純に'\n'だけ渡されたときに無視するようにすると、改行だけのやつ(fnlみたいなやつ)は捨てられてしまうので(ログに出すことしか考えていないので、許容できる場面もあると思うけど)簡単に対応しておく。
- 前回の出力が改行じゃないときは無視(PRINT_ITEM_TO->PRINT_NEWLINE_TOで呼ばれる場合)
- それ以外は空文字列を出力
まず結論。
dbusが使える環境で、kdewalletmanagerを起動した状態で、
すればいける(環境変数の値は別のでもいいかもしれないけど調べてない)
KDE_SESSION_VERSION=4 KDE_FULL_SESSION=true /opt/TweetDeck/bin/TweetDeck
以下経緯など
私のマシンでは、kubuntuのKDE4(4.2.1)はちょっと重いので
プログラムを書くのがメインな時はawesomeを使ってみることにした。
(まあ、それでも4.1.xの時と比べたらだいぶマシになった)
そこで困ったのが、AIRアプリであるTweetDeckが動かないこと。
WindowsでもLinuxでも動いて、しかもグループ分けが便利なので気に入って使ってる。
起動すると、次のようなメッセージが出て、画面は表示されるものの使えない状態になる。
Adobe AIRはいまのところKDEとGnomeしかサポートしていないらしい。
$ /opt/TweetDeck/bin/TweetDeck
Unknown desktop manager, only Gnome and KDE are supported
.
試しに
KDEWM=/usr/bin/awesomeにして、KDEで使うWindow ManagerをawesomeしたらTweetDeckも動くけど、なんかしっくりこない。
しかたがないので、awesome単体で使える方法を調べることにした。
KDEでTweetDeckを起動するとKwalletが動くので、手動でkwalletmanagerを起動してから
TweetDeckを起動してみたが、また同じメッセージが出てだめだった。
straceを使ってKDEから起動するときと、awesome環境から起動するときの違いをみてみたら、
どうもdbusでkwalletを探してるっぽいことが分かった。
でも、kwalletmanagerを起動しておけば、ちゃんと見つけられるし、
$ qdbus org.kde.kwalletd /modules/kwalletd org.kde.KWallet.localWallet
kdewallet
awesome環境で起動するときは、そもそもkwalletを探していないようなので不足があるようだ。
何か無いかとAIRのディレクトリを探ろうかと思ったら、いきなりlibCore.soを見つけたので、
おもむろにstrings libCore.so | grep -i kdeしてみたら、
KDE_SESSION_VERSION, KDE_FULL_SESSIONが出てきた。
こいつらにKDEで見た値を入れたら動いてしまった。