hints-ext 更新しました
更新内容は
- inline style 禁止 対策
- 面積のないElementが 欠ける件、実質問題なさげなレベルまで改善
- ラベル再配置(ラベルが重ならないようにする機能)
- 高速化(10倍くらいになった)
- ラベルの移動処理変更
- 細々と微調整
です。
vimperator/hints-ext.js at master · caisui/vimperator · GitHub
inline style 禁止
基本 CSP による inline style禁止 対策です。
また、コンテンツのcssの影響を受けなくなったので、!importが多様されているページでも崩れてしまうことがなくなりました。
ちなみに、test で使った簡便なCSPを吐く http server はこんなです。
面積のないElementが 欠ける
hints-ext について - caisuiの日記の件です。
力技で組込んでみましたが、10ms程度しか差異がでなかったので採用しました。
対策前 [パソコン], [PC周辺機器]等の部位が欠けています。
「解決」でなく「実質問題無い」としているのは、子孫ノードすら面積が無い(あるいは子孫が存在しない)ものは検知できてないからです。
しかし、見えていない Element なので、実質問題無いかなとしています。
従来の方式を望む場合は、
hints.fixRect0 = false;
とすれば、戻ります。
hints-ext について
現在、特定条件を満たした node が ヒントとして表示できません。
欠落に気付くことは困難なため、使用しないほうが良いと思います。
上記、"Diary"画像のリンクが奇数が表示できていないと思います。
(Windows Xp Windows 8 で確認)
a タグだけ ごまかすなら
style -name=anchor0 * a::after{ display: block; position: absolute; width: 1px; height: 1px; content: "";}
でそれっぽく改善しますが、layoutが壊れるとこがあるかもしれません。
原因
nsIDOMWindowUtils.nodesFromRect の仕様変更により、面積0(height or width 0)の Node が無視されるようになったようです。(多分 24 から 少なくとも 17は 面積0でも 出ている)
hints-ext は、nsIDOMWindowUtils.nodesFromRect を利用することにより、速度を稼いでいます。どうしましょうかね…。
Smooth Scroll
vimperator/smooth-scroll.js at master · caisui/vimperator · GitHub
buffer の Smooth Scroll 化です。
hjkl,gg,G等ほぼ全てが Smooth Scroll になります。
ただし、
デフォルトのスクロース時間は、300ms です。
変更したい場合は、
let smooth_scroll_duration=200
で変更できます。
以下変更にあたって、bufferの挙動変更点です。
- window決め打ち系(g,GG等) の スクロール対象も hjklと同様 caret 位置から遡る
- frame,iframeも遡り scrollbarを探します。
- 画面外スクロールバーは無視
これ mozRequestAnimationFrame を使ってみたのですが、
私の環境では60fpsでています。
最後に、問題点です。
他のscroll と干渉(競合?)します。
アニメーション描画の都合上途中で、
他のスクロールが発生しても影響を受けずにそのまま続きを描写します。
どうしても、途中で操作したいなら、
buffer経由
あるいは
plugins.smoothScroll.scrollBy(node, x, y);
や
plugins.smoothScroll.scrollTo(node, x, y);
を 経由して干渉する必要があります。
hints-ext 更新しました。
hints-ext.js を 更新しました。
https://github.com/caisui/vimperator/blob/master/plugin/hints-ext.js
更新内容はざっくり 以下2点です。
- Hint Node が document から 破棄されても、そのまま動くように修正
- 高さを持つ ノードを子孫に持つ インラインノードの 表示方法の変更
1 は、document を 読み込み中に HaH を表示すると 動作しなくなることがある問題の改修です。
また、style sheet が 遅延して読み込みまれてがっつり位置がズレても、再配置できるように
redraw 関数を追加しました。(末尾 map の サンプルを参照)
2 は、
<a href="#"><img src="..."/></a>
のような Node 対策です。
となっていたものが
となります。
デフォルトで ON なので、以前のよう(=無効)にしたい場合は、
rc file に
let disable_adj_inline=1
で 無効になります。
最後に、hint の マップ設定例です。hints-ext.js を load後に指定して下さい。
" runtimepath 配下の pluginを全て読み込む loadplugins js<<END (function() { // hint の 再描画 hints.addSimpleMap("<C-l>", function() { this.redraw(); }); // hint node 重なり除去 hints.addSimpleMap("<C-S-l>", function() { this.relocation(); } ); // 誤爆防止 hints.addSimpleMap(["<C-n>", "<C-t>", "<C-f>", "<C-g>"], function() { }); // インライン ノードの表示方法をトグル hints.addSimpleMap("<C-i>", function() { this.toggleInlineAdj(); }); })(); END
vimperator3.6 について
vimperator3.6で e4x を除去 し Template String で 代替するパッチがマージされました。
結果、pluginが影響を受けますので思い付くままに記載したいと思います。
vimperator 3.5で困ってないかたは、 バグの洗い出しや、pluginの 対応が終るまで移行しないほうが良いと思います。
(javascript.options.xml.chrome=true でも軽微ですが、副作用があります)
Template Stringの 正しい仕様は、http://wiki.ecmascript.org/doku.php?id=harmony:quasisを参照下さい。
現段階において、Firefox にTemplate Stringは実装されいません。
vimperator side で 現行javascriptで動くように変換して実行しています。
5行で書かれた Template String は 5行で変換してるので、エラー行番号は似た位置が表示されるはずですが、
記述したそのものが実行されるわけではありませんので plugin 開発においてやっかいな要因になると思います。
以下 私の理解した範囲で実装したものを説明します。
Template String とは
一言で言うと、heredoc っぽい形式で記述できる関数の糖衣構文です。
tag`Literal1${obj1}Literal2${obj2}Literal3`
と記載すると
tag({raw: ["Literal1", "Literal2", "Literal3"],cooked: ["Literal1", "Literal2", "Literal3"]}, [(obj1), (obj2)])
に相当します。
(cooked, raw は、Literal部位のエスケープシーケンスの解釈が変わります。詳しくは、http://wiki.ecmascript.org/doku.php?id=harmony:quasis を参照下さい。)
また、tagは省略することができ、その場合はraw tag 相当が適用されます。
(raw tag は、単純にLiteral と obj を 連結していく tagです)
var name = 'hoge'; var s = `こんにちは${hoge}さん さようなら${hoge}さん`;
は、
var name = 'hoge'; var s = ("こんにちは" + (hoge) + "さん\n\ さようなら" + (hoge) + "さん");
に相当します。
tag の 自作
関数を作成すれば使えます。
function test(a, b) { var raw = a.raw; var i, j, s = ""; for (i = 0, j = b.length; i < j; i++) s += raw[i] + "(" + String(b[i]) + ")"; s += raw[i]; return s; }
で 埋め込み変数を括弧で囲うraw tag の 亜種が完成となります。
また、返り値が文字列である必要もありませんので、
function dom(a, b) { var raw = a.raw; var i, j, s = ""; // サンプル用の 簡易実装のため文脈依存のエスケープ処理はしてません for (i = 0, j = b.length; i < j; i++) s += raw[i] + String(b[i]); s += raw[i]; var ps = new DOMParser; var doc = ps.parseFromString(s, "text/html"); var range = document.createRange(); range.selectNodeContents(doc.body); return range.extractContents(); } var node = dom`<table> <tr><td>1</td><td>2</td></tr> <tr><td>1</td><td>2</td></tr> <tr><td>1</td><td>2</td></tr> <tr><td>1</td><td>2</td></tr> </table>`;
で DOMが生成できます。
plugin について
e4x を 使用しているものは全て動きません。
e4x 固有の文法を使用している場合は、代替案を模索することになります。
以下 変更 例です。
dom の生成
util.xmlToDom(<a href={url}>{text}</a>, document)
↓
util.xmlToDom(xml`<a href=${url}>${text}</a>`, document)
plugin help
var INFO = <plugin name="hoge" version="0.1.0" href="xxxx" summary="yyy" xmlns="http://vimperator.org/namespaces/liberator"> 省略 </plugin>;
↓
var INFO = xml`<plugin name="hoge" version="0.1.0" href="xxxx" summary="yyy" xmlns="http://vimperator.org/namespaces/liberator"> 省略 </plugin>`;
XUL生成
liberator.echo(<datepicker type="grid" xmlns={XUL}/>)
↓
liberator.echo(xml`<datepicker type="grid" xmlns={XUL}/>`)
あるいは、
liberator.echo(xml`<xul:datepicker type="grid"/>`)
用は、xmlns:html と xmlns:xul と xmlns:nsをこっそり定義しちゃってます。
heredoc
node.style.cssText = <![CDATA[ color: red; border: 1px solid blue; ]]>.toString();
↓
node.style.cssText = ` color: red; border: 1px solid blue; `;
e4x の連結
結構差異がでます。(operator + や operator += は できません)
function hoge1(node1, node2) { return <pre>{node1 + node2}</pre> } function hoge2(array) { var x = new XML; for (var i = 0, j = array.length; i < j; i++) { x += array[i]; } return x; }
↓
function hoge1(node1, node2) { return xml`<pre>${node1}${node2}</pre>; } function hoge2(array) { var x = xml``; for (var i = 0, j = array.length; i < j; i++) { x = xml`${x}${array[i]}`; } return x; }
その他文法
@xx や .* 等は、DOMParserを使用してdomに変換すれば、似たことができます。
muttatorで行こう!
muttator の 雑感 と独自の マップ一覧 と mode の 状態遷移をまとめました。
雑感
NORMAL mode
- j/k :[選択 messege の移動]
- +/- or
/ :[preview panel の ページスクロール] - n : Thunder Bird 標準ショートカットですが、未読ジャンプ * spam folder 無視
- d : メール削除
- s : メールの移動
- ! : spam mark
- r,f,c : メッセージ作成(返信、転送、新規)
あたりを押さえておけば使えると思います。
preview panel を もっと細かく制御したいなら、
ただし、
(HINTS, CARET, VISUAL, SEARCH を 抜けた後に戸惑うことになるかもしれません)
COMPOSE mode(=メッセージ作成)
- map が少ないので全部覚えちゃいましょう!(一覧は後述)
- COMPOSE mode で focus が 残ってしまい、未割当 keyで文字入力ができてしまう。
- 本文でTEXT mode, VISUAL mode, INSERT mode の map が 動かない
focus の 問題は、以下のスクリプトでごまかしています。
js <<CODE liberator.registerObserver("modeChange", function modeChange([oldMode], [newMode]) { if (newMode === modes.COMPOSE) { Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager) .clearFocus(window); } }); CODE
本文の問題は、放置してますl:)
NORMAL モード に おける固有 map
a | メッセージの差出人をアドレス帳に追加 mail adress のみ ("hoge@example.com" のような"xxxxx |
message mode へ 移行 | |
Thunder Bird に まる投げ | |
t | スレッドを全て選択 |
d, |
選択メッセージを削除 |
j, |
次のメッセージを選択(閉じたスレッド内はスキップ) |
k, |
前のメッセージを選択(閉じたスレッド内はスキップ) |
gj | 次のメッセージを選択(閉じたスレッドは展開して選択だと思うけどエラー) |
gk | 前のメッセージを選択(閉じたスレッドは展開して選択だと思うけどエラー) |
J, |
次の未読を選択 * spam メールも対象になる * |
K | 前の未読を選択 * spam メールも対象になる |
* | 同じ差出人の次のメッセージへ移動 |
# | 同じ差出人の前のメッセージへ移動 |
c | 新しメッセージを作成 |
C | 選択メッセージの差出人に対して 新しいメッセージの作成 |
r | 選択メッセージの差出人に返信 |
R | 選択メッセージの差出人と Cc(?)に返信(menu の"全員に返信" に 相当) |
f | 選択メッセージを転送メッセージする |
F | 選択メッセージを転送メッセージする(インライン) |
preview メッセージを line down | |
preview メッセージを line up | |
+ | preview メッセージを page down |
- | preview メッセージを page up |
u | 元に戻す |
やり直す | |
gm | 全アカウントの新着メッセージを受信 |
gM | 現在のアカウントの新着メッセージを受信 |
o | フォルダを指定して移動 |
s | 選択メッセージを 移動 |
S | 選択メッセージを コピー |
選択メッセージをアーカイブ | |
! | 選択メッセージを迷惑メールマークをトグル |
gi | 受信トレイに移動 |
次のフォルダへ移動 | |
前のフォルダへ移動 | |
次の未読があるフォルダへ移動 | |
前の未読があるフォルドへ移動 | |
za | 選択メッセージのスレッドを展開/折り畳む |
zc | 選択メッセージのスレッドを折り畳む |
zo | 選択メッセージのスレッドを展開 |
zr,zR | すべてのスレッドを展開 |
zm,zM | すべてのスレッドを折り畳む |
menuの[移動(G)]-[進む(F)]に相当 | |
menuの[移動(G)]-[戻る(B)]に相当 | |
gg | フォルダの先頭メッセージを選択 |
G | フォルダの最終メッセージを選択 |
l |
1-5: tag 付与 1-5 r: 既読 s: star |
T | カレントフォルダの未読を既読にする |
全ての未読メッセージを既読にする | |
h | ヘッダの表示形式をトグル変更 |
x | html 表示を トグル変更 |
y |
y: author s: subject #: message id t: 宛先 r: ccっぽい(未確認) u: rss feed の url っぽいけど 動かない |
p | rss message を ブラウザで開く |
COMPOSE mode
: | 同じみコマンドライン |
e | editorで開く |
y | いますぐ送信 |
Y | 後で送信 |
t | To(宛先) field に focus となっているが実際は、field の 先頭 input box に focus |
s | Subject(件名) に focus |
i | 本文にfocus |
q | 閉じる。保存していないときは、確認 |
Q,ZQ | 閉じる。保存の有無は無視 |
vimperatorでもifがしたい!
Vimperator Advent Calendar 2012 9日目担当 caisui です。
ローカルパッチで 作成していた if コマンドを pluginに移植してみました。
改変部位が io.source のため 一工夫入れないと使えませんがご了承願います。
https://gist.github.com/4239753#file_cmd_if.js
特徴として
- 評価するのは、javascript
- heredoc サポート(最後の行を評価結果として判定)
- elseif に 変数を引き継ぎする
- 無いよりまし程度だけど、commandlineでも 動作
- vim の if と違い 実行しないブロックのコマンドもパースする(heredocの関係で同等にすることは断念しました)
細かい仕様は、
https://gist.github.com/4239753#file_test.vimp
から読みとってください!
以下は、rc晒しです。参考になる部位があれば何よりです。
(ざっくりですがコメントも入れました)
" vim: set ft=vim: " 以下2行を アンコメントで noplugin 相当でFirefox を 起動 "js liberator.commandLineOptions.noPlugins=true ":finish " io.source を 上書き so ~/vimperator/gist/4239753/cmd-if.js " if が 有効な io.source で 実行 exstr <<RC " runtimepath 初期化 set runtimepath=~/vimperator/github,~/vimperator/common " profile name 固有 設定 plugin を 読み込む execute "so ~/vimperator/" + liberator.profileName + ".vimp" execute "set runtimepath+=~/vimperator/" + liberator.profileName " migemo が 有効なら hint の 絞り込みを変更 if window.migemo set hintmatching=custom endif set hc=hjklasdfgyuiopqwertnmzxcvb set nohlsearch set nofocuscontent set noautocomplete nnoremap <silent> g# :b#<cr> " 某plugin map 割り当て nnoremap <silent> <S-b> :pi tab<CR> nnoremap <silent> <c-s-j> :pi console<CR> nnoremap <silent> <c-j> :pi download<CR> nnoremap <silent> ,b :pi hatenta-bookmark<cr> nnoremap <silent> ,s :pi noscript<cr> nnoremap <silent> ,a :pi tab-history<CR> cnoremap <silent> <C-f> :pi command-mru<cr> nnoremap / :grep2<space> " カレンダー表示 command cal :js liberator.echo(<datepicker type="grid" xmlns={XUL}/>) " MOW で 右クリック有効化 js document.getElementById("liberator-multiline-output").setAttribute("contextmenu", "contentAreaContextMenu") " 某プラグイン 諸設定 let use_hintchars_ex=2 let use_hints_ext_hinttags=1 let use_hints_ext_extendedhinttags=1 let use_hints_ext_caret="c" let use_hints_ext_visual="v" let typescript_path="~/vimperator/lib/typescript/" " nomenu(menu非表示)状態から menuを出すと1行ずれるので overlay 化 style -name=menu chrome://browser/content/browser.xul <<CSS #toolbar-menubar[autohide="true"] { background-color:transparent!important; position:fixed; z-index:999999; left:1ex; top:1ex; } #toolbar-menubar[autohide="true"] #main-menubar { background-color:rgba(0,0,0,.7)!important; padding: 1ex!important; border-radius:4px; } #toolbar-menubar[autohide="true"] #main-menubar>menu { color: white!important; border-radius: 2px; transition: .5s background; } #toolbar-menubar[autohide="true"] #main-menubar>menu[_moz-menuactive="true"] { -moz-appearance:none!important; background-color: rgba(255,255,255,.5)!important; } CSS noremap <silent> <C-h> :tabh back<CR> noremap <silent> <C-l> :tabh forward<CR> " tree style tab 用 設定 if window.TreeStyleTabService style -name=floatbox chrome://browser/content/browser.xul .liberator-floatbox{z-index: 9999;} let mapleader=":tst<space>" nmap <silent> ,t <Leader>open<Space> nmap <silent> ,T <Leader> nmap <silent> zj <Leader>next<cr> nmap <silent> zk <Leader>prev<cr> nmap <silent> zh <Leader> goto parent<cr> nmap <silent> zl <Leader> goto cfirst<cr> nmap <silent> zL <Leader> goto clast<cr> nmap <silent> zH <Leader> goto root<cr> nmap <silent> zK <Leader>move -r<cr> nmap <silent> zJ <Leader>move<cr> nmap <silent> d <Leader> bdelete<cr> nmap <silent> zd <Leader> delete!<cr> nmap <silent> >> <Leader> shift<cr> nmap <silent> << <Leader> unshift<cr> nmap <silent> gzz <Leader>scroll --pos=center<cr> nmap <silent> gzt <Leader>scroll --pos=top<cr> nmap <silent> gzb <Leader>scroll --pos=bottom<cr> nmap <silent> zn <Leader>goto pnext<cr> nmap <silent> zp <Leader>goto pprev<cr> nmap <silent> zN <Leader>goto rnext<cr> nmap <silent> zP <Leader>goto rprev<cr> nmap <silent> gp <Leader>paste<cr> unlet mapleader endif "ここでplugin 読み込み loadplugins " 以下plugin 依存諸設定 if plugins.hintsExt hi -append HintExt font-family: Consolas; hi HintExt::before opacity: .6; endif hi StatusLineSecure -append font-weight: bold; coffee <<CODE userContext.__defineGetter__ "doc", () -> content.document userContext.__defineGetter__ "win", () -> content.window s = ",t" map = mappings.get modes.NORMAL, s if map [modes.CARET, modes.VISUAL].forEach (m)-> mappings.remove m, s mappings._user[m].push map map.modes.push m if plugins.hintsExt hints.addSimpleMap "<C-l>", () -> this.relocation() CODE RC