2.3への対応
2.2,2.3 どちらでも動くと思います。
エラーは、出ていないものの動いてないものもあると思うので、
気づいたら直していきます。
grep
- 2.3対応
- options に あったスコープ定義がOptionに移動した模様
- literal=1に変更
- 「ringo\ ha」と入力していたところを「ringo ha」で済む
- frame を ロードしてもキャッシュを破棄するように変更
- 「bottom」や「top」がもう少ししっかり出たらいいな
// vim: set fdm=marker: (function(){ //{{{ config const cmd_name = ["grep"]; const match_style = "color:red;font-weight:bold;"; const abbr_style = "color:blue;font-weight:bold;"; const grep_info_attr = "__vmp_grep_cmd"; const use_hook_search_map = true; const use_show_echo = false; const use_clear_editor_range = true; const option_scroll = "grep_scroll_position"; const option_grep = "grep_option"; const option_highlight = "hlgrep"; const scope = Option.SCOPE_GLOBAL || options.OPTION_SCOPE_GLOBAL; //{{{ options (function(){ const position_list = { "top": [0, -1], "center": [50, -1], "bottom": [100, -1], "auto" : [-1, -1], }; const grep_groups={ "engine":{ n: "normal search", r: "regex search", x: "xul/migemo search", }, "flags":{ i: "ignore case", m: "multiple lines", }, }; options.remove(option_scroll); options.add([option_scroll],"grep scroll postion", "string","center", { scope: scope, completer:function(context){ context.completions = ([[x,""] for(x in position_list)]); }, validator:Option.validateCompleter, }); options.get(option_scroll).__defineGetter__("vhPercent",function() position_list[this.value]||[-1,-1]); options.remove(option_grep); options.add([option_grep], "grep option", "charlist", "imx", { scope: scope, setter:function(value){ let list = []; for(let [,c] in Iterator(value||[])){ if(list.indexOf(c)===-1) list.push(c); } return list.join(""); }, completer:function(context){ for(let [grp_nm, grp_opt] in Iterator(grep_groups)){ context.fork(grp_nm,0,this,function(context){ context.title[0] = grp_nm; context.completions = [val for(val in Iterator(grp_opt))]; }); } }, validator:function(val) Option.validateCompleter.call(this,val) && [x for([x,] in grep_groups.engine)].some(function(n) val.indexOf(n) >= 0) , }); options.remove(option_highlight); options.add([option_highlight],"grep highlight", "boolean", false, { scope: scope, setter:function(value){ if(value){ let info = get_cache(); if(info) show_highlight(info.list); } else clear_highlight(); return value ? true : false; }, completer:function()[ [true , "show highlight"], [false, "hide highlight"], ], }); })(); //}}} //{{{core const vimp = "liberator-completions"; let finder = Cc["@mozilla.org/embedcomp/rangefind;1"] .getService(Ci.nsIFind); const option_list = "imxnr"; const gFm = Cc["@mozilla.org/focus-manager;1"] .getService(Ci.nsIFocusManager); //}}} //}}} function range2string(r, max){ let txt = r.toString(); let so = r.startOffset; let eo = r.endOffset; let et = r.endContainer.textContent; let st = r.startContainer.textContent; let max = (arguments.callee.max/2-2) || 0; return { abbr : so > max, prev : (so > max ? st.substr(so - max, max) : st.substr(0, so)).replace(/\s+$/,"\xa0"), text : r.toString(), next : et.substr(eo, max*2).replace(/^\s+/,"\xa0"), }; } function get_word_max(){ let win = document.getElementById(vimp).contentWindow; let fontSize = win.getComputedStyle(win.document.body,'').fontSize.replace("px",""); return Math.floor(document.width / fontSize); } let process = [function(i,text){ let r = range2string(i.item.range); return <><div style="position:absolute;"> {r.abbr ? <span style={abbr_style}>~~</span> : ""} {r.prev} <span style={match_style}>{r.text}</span> {r.next} </div> </>; }, function() <span></span>]; function iteratorFrame(win){ yield win; for(let f1 in util.Array.itervalues(win.frames)){ for(let f2 in arguments.callee(f1)) yield f2; } } function create_ranges(win){ let doc = win.document; let body = doc.body; let count = body.childNodes.length; let searchRange = doc.createRange(); let startPt = doc.createRange(); let endPt = doc.createRange(); searchRange.setStart(body, 0); searchRange.setEnd(body, count); startPt.setStart(body, 0); startPt.collapse(true); endPt.setStart(body, count); endPt.collapse(true); return [searchRange, startPt, endPt]; } function normal_find(win, word, option){ let doc = win.document; let list = []; let [whole,start,end] = create_ranges(win); while(result = finder.Find(word, whole, start, end)){ list.push(result); start = doc.createRange(); start.setStart(result.endContainer, result.endOffset); start.collapse(true); } return list; } function normal_grep(word, option){ let result,ret=[]; finder.caseSensitive = !/i/.test(option); for(let win in iteratorFrame(content.window)){ let list = []; let words = word.split(" "); //unique words = words.sort(); let(prev) words = words.filter(function(n) prev !== (prev=n)); for([,w] in Iterator(words)){ list = list.concat(normal_find(win, w)); } list.sort(function(a,b) a.compareBoundaryPoints(Range.START_TOSTART, b)); ret = ret.concat(list); } return ret; } //{{{ function regexp_grep_core(re){ let result,ret=[]; finder.caseSensitive = true; for(let win in iteratorFrame(content.window)){ let list = []; let [whole,start,end] = create_ranges(win); let words = whole.toString().match(re)||[]; //unique words = words.sort(); let(prev) words = words.filter(function(n) prev !== (prev=n)); for([,w] in Iterator(words)){ list = list.concat(normal_find(win, w)); } list.sort(range_compare); ret = ret.concat(list); } return ret; } function regexp_grep(word, option){ return regexp_grep_core(RegExp(word, option)); } function migemo_grep(word, option){ let re = new RegExp(window.migemo.query(word), option); return regexp_grep_core(re); } //}}} function range_compare(a,b) a.compareBoundaryPoints(Range.START_TO_START, b) || a.compareBoundaryPoints(Range.END_TO_END, b) function range_compare_d(win){ win = win || content.window; let list = [w.document for(w in iteratorFrame(win))]; return function(a,b){ let n1 = a.startContainer.ownerDocument; let n2 = b.startContainer.ownerDocument; let ret=0; if(n1 === n2) return a.compareBoundaryPoints(Range.START_TO_START, b) || a.compareBoundaryPoints(Range.END_TO_END, b); for(let [,n] in Iterator(list)){ if(n===n1) return -1; else if(n===n2) return 1; } }; } let mode_func = { }; mode_func.n = normal_grep; mode_func.r = regexp_grep; mode_func.x = migemo_grep; //{{{ range cache function get_cache(){ return content.document[grep_info_attr]; } function clear_cache(event){ var br = event.currentTarget; br.contentWindow.document[grep_info_attr] = null; br.removeEventListener(event.type, arguments.callee, true); } function get_grep_info(arg){ let m,word,flags,mode,num; let re = new RegExp( <>^((\d*)([{option_list}]*)/)?([^/]+)(/([{option_list}]*))?$</>.toString() ,"i"); if(m=re.exec(arg)){ let s = ""; word = m[4]; num = m[2]||0; if(!m[1] && !m[5]){ s = options[option_grep]; }else if(m[6]){ s = m[6]; }else if(m[3]){ s = m[3]; } flags = ""; if(/i/.test(s)) flags += "i"; if(/m/.test(s)) flags += "m"; if(m=/.+([xnr])/.exec(options[option_grep]+s)){ mode = m[1]; } } let option = <>{flags}{mode}</>.toString(); let info = get_cache(); if(info){ if(info.word === word && info.option === option){ info.index = num; info.enabled = false; return info; } }else{ let br = gBrowser.getBrowserForDocument(content.document); br.addEventListener("unload", clear_cache, true); } let func = mode_func[mode]; if(!func){ liberator.echoerr(<>{mode} is not support</>.toString()); return; } let list = func(word, flags + "g"); info = {list:list, index:num, word: word, option: option}; content.document[grep_info_attr] = info; return info; } function getSelectionControllerFromWindow(view){ let selectionController = null; try{ selectionController = view .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell) .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsISelectionDisplay) .QueryInterface(Ci.nsISelectionController); }catch(ex){} return selectionController; } function checkEditableElement(node){ let ret = false; try{ node.QueryInterface(Ci.nsIDOMNSEditableElement) ret = true; }catch(ex){} return ret; } function getEditor(node){ while(node){ if(checkEditableElement(node)){ return node.editor; } node = node.parentNode; } return null; } function getSelectionControllerFromRange(aRange){ let node = aRange.startContainer; let editor = getEditor(node); return editor ? editor.selectionController : getSelectionControllerFromWindow(node.ownerDocument.defaultView); } function clearEditorAllSelections(win, aType){ win = win || content.window; aType = aType || Ci.nsISelectionController.SELECTION_NORMAL; for(let w in iteratorFrame(win)){ let list = w.document.getElementsByTagName("*"); for(let [,n] in Iterator(list)){ if(checkEditableElement(n)){ let editor = n.editor; if(editor){ let selection = editor.selectionController.getSelection(aType); if(selection.rangeCount>0){ selection.removeAllRanges(); } } } } } } function grep_jump(info){ if(info.list.length == 0){ liberator.echoerr(<>no match "{info.option}/{info.word}"</>,commandline.DISALLOW_MULTILINE); return; } let n = info.list[info.index]; if(!n){ liberator.echoerr(<>index error "{info.index}"</>,commandline.DISALLOW_MULTILINE); return; } let win = n.startContainer.ownerDocument.defaultView; if(gFm.focusedWindow){ if(use_clear_editor_range) clearEditorAllSelections(); gFm.focusedWindow.getSelection().removeAllRanges(); } let selectionController = getSelectionControllerFromWindow(win); if(!selectionController) return; //{{{ editable element let editor = getEditor(n.startContainer); if(editor){ let selectionController = editor.selectionController; let selection = selectionController.getSelection(Ci.nsISelectionController.SELECTION_NORMAL); selection.removeAllRanges(); selection.addRange(n); selectionController.setDisplaySelection(Ci.nsISelectionController.SELECTION_ATTENTION); } //}}} let selection = selectionController.getSelection(Ci.nsISelectionController.SELECTION_NORMAL); selection.removeAllRanges(); selection.addRange(n); gFm.moveFocus(win, null, Ci.nsIFocusManager.MOVEFOCUS_CARET, Ci.nsIFocusManager.FLAG_NOSCROLL | Ci.nsIFocusManager.FLAG_NOSWITCHFRAME); selectionController.setDisplaySelection(Ci.nsISelectionController.SELECTION_ATTENTION); selectionController.repaintSelection(Ci.nsISelectionController.SELECTION_NORMAL); info.enabled = true; let(op=options.get(option_scroll).vhPercent) selection .QueryInterface(Ci.nsISelection2) .scrollIntoView(Ci.nsISelectionController.SELECTION_ANCHOR_REGION,true,op[0],op[1]); win.focus();// nsIFocusManager の focusedWindow を 更新 if(use_show_echo){ range2string.max = get_word_max(); liberator.echo(process[0]({item:{range:n}},"").*,commandline.DISALLOW_MULTILINE); } } function bi_search(list, n, backword){ let lhs = 0,rhs = list.length,mid=0,ret; let comp = range_compare_d(content.window); while(1){ if(mid===(mid=Math.floor((lhs+rhs)/2))){ if(mid === 0 && ret < 0) return -1; else if(mid === list.length-1 && ret > 0 && !backword) return mid+1; else return mid; } ret = comp(n, list[mid]); if(ret < 0) rhs = mid; else if(ret > 0) lhs = mid; else{ return backword ? mid - 1 : mid; } } } function get_grep_list_index(info, isReverse){ info = info || get_cache(); let win = gFm.focusedWindow; let selection = win.getSelection(); let r; if(selection.rangeCount === 0){ r = win.document.createRange(); r.setStart(win.document.body, 0); }else{ r = selection.getRangeAt(0); } let index = bi_search(info.list, r, isReverse); return index; } function grep_next(){ let info = get_cache(); if(!info) return; info.index = get_grep_list_index(info); let show_msg = false; if(++info.index >= info.list.length){ info.index = 0; window.setTimeout(function(){ liberator.echoerr("bottom!",commandline.DISALLOW_MULTILINE); },100); } grep_jump(info); return true; } function grep_prev(){ let info = get_cache(); if(!info) return; info.index = get_grep_list_index(info, true); if(info.index < 0){ info.index = info.list.length-1; window.setTimeout(function(){ liberator.echoerr("top!", commandline.DISALLOW_MULTILINE); },100); } grep_jump(info); return true; } //}}} //{{{ highlight function show_highlight(list){ for(let [,r] in Iterator(list)){ let selectionController,n; n = r.startContainer; let editor = getEditor(n); selectionController = editor ? editor.selectionController : getSelectionControllerFromWindow(n.ownerDocument.defaultView); if(selectionController){ let selection = selectionController.getSelection(Ci.nsISelectionController.SELECTION_FIND); selection.addRange(r); } } } function clear_selection_find(win){ win = win||content.window; let selectionController = getSelectionControllerFromWindow(win); if(selectionController){ let selection = selectionController.getSelection(Ci.nsISelectionController.SELECTION_FIND); selection.removeAllRanges(); } } function clear_highlight(){ for(let w in iteratorFrame(content.window)){ clear_selection_find(w); } clearEditorAllSelections(null, Ci.nsISelectionController.SELECTION_FIND); } //}}} let T={ name : cmd_name , desc :"grep page", action:function(args){ let info = get_grep_info(args[0]); if(info){ if(options[option_highlight]){ clear_highlight(); show_highlight(info.list); } grep_jump(info); } }, option:{ } }; T.option.literal = 0; T.option.completer = function(context, args){ try{ let info = get_grep_info(args[0]); if(!info || info.list.length == 0) return; context.process = process; context.keys={text:"text",description:"text"}; context.match = function(str){ return true; }; range2string.max = get_word_max(); let query = info.query; context.completions = info.list.map(function(n,i){ return { text: <>{i}{info.option}/{info.word}</>.toString(), range: n } }); }catch(ex){liberator.echoerr(ex);} }; commands.addUserCommand(T.name, T.desc, T.action, T.option, true); if(use_hook_search_map)//{{{ { function hook_function(obj, attr, func){ const org = "__original"; let original = obj[attr]; if(org in original) original = original[org]; let ret=function(){ if(!(func.apply(this,arguments)===true)){ original.apply(this,arguments); } }; ret[org] = original; obj[attr] = ret; } map = mappings.get(modes.NORMAL,"/"); hook_function(map, "action", function(){ let info = get_cache(); if(info) info.enabled = false; }); map = mappings.get(modes.NORMAL,"n"); hook_function(map, "action", function(){ if(grep_info_attr in content.document){ let info = get_cache(); if(info&&info.enabled){ grep_next(); return true; } } }); map = mappings.get(modes.NORMAL,"N"); hook_function(map, "action", function(){ if(grep_info_attr in content.document){ let info = get_cache(); if(info&&info.enabled){ grep_prev(); return true; } } }); } //}}} })();
hints-overfow
- 2.3対応
- スクロール系関数の位置が変更になった模様
(function(){ const attr_name="vimperator_scroll_node"; const aMap = "d"; const bufferContext = buffer.evaluateXPath; function iter_quereySelector(selector,context){ context = context || content.document; let e=context.querySelectorAll(selector); for(let i=0,j=e.length;i<j;++i){ yield e[i]; } } function hook(obj, attr, func){ if(!(attr in obj)){ liberator.echoerr(<>{attr} is not found</>); return; } var orgFunc = let(f=obj[attr]) f.original || f; obj[attr] = function(){ if(func.apply(this,arguments) === false){ orgFunc.apply(this,arguments); } } obj[attr].original = orgFunc; } var OverFlowScroller ={ tags:function(){ OverFlowScroller.addMark(content.window); return "//*[@"+attr_name+">'0']"; }, addMark:function(aWindow){ Array.forEach(aWindow.document.body.getElementsByTagName("*"),function(e){ if((e.offsetHeight !== e.scrollHeight) || (e.offsetWidth !== e.scrollWidth)){ e.setAttribute(attr_name,"1"); } }); Array.forEach(aWindow.frames, arguments.callee); }, removeMark:function(aWindow){ if(!aWindow) aWindow=content.window; var doc=aWindow.document; for(let x in iter_quereySelector(<>*[{attr_name}]</>.toString())){ x.removeAttribute(attr_name); } Array.forEach(aWindow.frames,arguments.callee); }, mark:function(e){ e.setAttribute(attr_name,"2"); liberator.echo("mark node!"); }, getElementCore:function(aWindow){ var e=aWindow.document.evaluate("//*[@"+attr_name+"='2']",aWindow.document,null,9,null).singleNodeValue; if(!e) for(var f in util.Array.itervalues(aWindow.frames)){ if(e = arguments.callee(f)) break; } return e; }, getElement:function() OverFlowScroller.getElementCore(content.window), action:{ scrollLines:function(aLines){ var e=OverFlowScroller.getElement(); if(!e) return false; OverFlowScroller.scrollVertical(e, "lines", aLines); return true; }, scrollPages:function(pages){ var e=OverFlowScroller.getElement(); if(!e) return false; OverFlowScroller.scrollVertical(e, "pages", pages); return true; }, scrollToPercent:function(x, y){ var e=OverFlowScroller.getElement(); if(!e) return false; if (x != null) e.scrollLeft = (e.scrollWidth - e.clientWidth) * (x/100); if (y != null) e.scrollTop = (e.scrollHeight - e.clientHeight) * (y/100); return true; }, scrollColumns:function(cols){ var e=OverFlowScroller.getElement(); if(!e) return false; OverFlowScroller.scrollHorizontal(e, "columns", cols); return true; }, scrollStart:function(x) OverFlowScroller.action.scrollToPercent(0, null), scrollEnd:function(x) OverFlowScroller.action.scrollToPercent(100, null), }, onEscape:function(){ OverFlowScroller.removeMark(); return false; } }; let(list=[ "scrollVertical", "scrollHorizontal", ]){ for(let [,a] in Iterator(list)) OverFlowScroller[a] = (a in Buffer) ? Buffer[a] : liberator.eval(a, bufferContext); } for(let [a,f] in Iterator(OverFlowScroller.action)){ hook(buffer, a, f); } let(a="onEscape") hook(events, a, OverFlowScroller[a]); hints.addMode(aMap, "overflow scroll", OverFlowScroller.mark, OverFlowScroller.tags); })();