diff --git a/NEWS b/NEWS index b9eaab68..abdac68a 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,10 @@
2007-xx-xx:
* version 0.5.1
+ * native / and ? search and n and N working again
* the URL in the status line can be selected with the mouse again
+ * the Windows default RC file is now ~/_vimperatorrc and the plugin
+ directory is ~/vimperator/plugin
* commandline history now works properly on Windows
* filename completion now works on Windows
* the Bookmarks Toolbar Folder is now read when bookmarks are first
diff --git a/chrome/content/vimperator/commands.js b/chrome/content/vimperator/commands.js
index 7474b27d..80a60526 100644
--- a/chrome/content/vimperator/commands.js
+++ b/chrome/content/vimperator/commands.js
@@ -682,6 +682,16 @@ function Commands() //{{{
help: "If [arg] is specified then limit the list to those marks mentioned."
}
));
+ addDefaultCommand(new Command(["noh[lsearch]"],
+ function(args)
+ {
+ vimperator.search.clear();
+ },
+ {
+ short_help: "Clear the current selection",
+ help: "TODO"
+ }
+ ));
addDefaultCommand(new Command(["norm[al]"],
function(args)
{
diff --git a/chrome/content/vimperator/find.js b/chrome/content/vimperator/find.js
index f61d2ec7..3d268012 100644
--- a/chrome/content/vimperator/find.js
+++ b/chrome/content/vimperator/find.js
@@ -11,9 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
-The Initial Developer of the Original Code is Shawn Betts.
-Portions created by the Initial Developer are Copyright (C) 2004,2005
-by the Initial Developer. All Rights Reserved.
+(c) 2006-2007: Martin Stubenschrott
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -28,443 +26,135 @@ the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/
-// Finder for vimperator
-// Author: Nigel McNie
-// Original Author: Shawn Betts
-//
-// The algorithm was taken from conkeror , but
-// extensively refactored and changed to behave like vim (naturally!)
-// The window to search in (which frame)
-//var gWin = null;
-//var gSelCtrl = null;
-
-//function highlight(range, node) {
-// var startContainer = range.startContainer;
-// var startOffset = range.startOffset;
-// var endOffset = range.endOffset;
-// var docfrag = range.extractContents();
-// var before = startContainer.splitText(startOffset);
-// var parent = before.parentNode;
-// node.appendChild(docfrag);
-// parent.insertBefore(node, before);
-// return node;
-//}
-
-// Clears the current selection
-// @todo this should be in vimperator.js, and not depend on searcher.gSelCtrl
-function clearSelection() {
- //var selctrl = gSelCtrl;
- var selctrl = vimperator.search.gSelCtrl;
- var sel = selctrl.getSelection(Components.interfaces.nsISelectionController.SELECTION_NORMAL);
- sel.removeAllRanges();
- gFindBar.highlightDoc();
-}
-
-// Sets what is currently selected
-// @todo as for clearSelection
-function setSelection(range) {
- try {
- var selctrlcomp = Components.interfaces.nsISelectionController;
- //var selctrl = gSelCtrl;
- var selctrl = vimperator.search.gSelCtrl;
- var sel = selctrl.getSelection(selctrlcomp.SELECTION_NORMAL);
- sel.removeAllRanges();
- sel.addRange(range.cloneRange());
-
- selctrl.scrollSelectionIntoView(selctrlcomp.SELECTION_NORMAL,
- selctrlcomp.SELECTION_FOCUS_REGION,
- true);
- }
- catch (e) {
- alert("setSelection: " + e);
- }
-}
-
-// Highlight find matches and move selection to the first occurrence
-// starting from pt.
-// @todo move into searcher and clean up
-function highlightFind(str, color, wrapped, dir, pt)
-{
- try {
- var gWin = vimperator.search.gWin;//document.commandDispatcher.focusedWindow;
- if (!gWin) {
- alert('gWin does not exist here...');
- alert(vimperator.search.gWin);
- }
- var doc = gWin.document;
- var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"].createInstance()
- .QueryInterface(Components.interfaces.nsIFind);
- var searchRange;
- var startPt;
- var endPt;
- var body = doc.body;
-
- finder.findBackwards = !dir;
-
- searchRange = doc.createRange();
- startPt = doc.createRange();
- endPt = doc.createRange();
-
- var count = body.childNodes.length;
-
- // Search range in the doc
- searchRange.setStart(body,0);
- searchRange.setEnd(body, count);
-
- if (!dir) {
- if (pt == null) {
- startPt.setStart(body, count);
- startPt.setEnd(body, count);
- } else {
- startPt.setStart(pt.startContainer, pt.startOffset);
- startPt.setEnd(pt.startContainer, pt.startOffset);
- }
- endPt.setStart(body, 0);
- endPt.setEnd(body, 0);
- } else {
- if (pt == null) {
- startPt.setStart(body, 0);
- startPt.setEnd(body, 0);
- } else {
- startPt.setStart(pt.endContainer, pt.endOffset);
- startPt.setEnd(pt.endContainer, pt.endOffset);
- }
- endPt.setStart(body, count);
- endPt.setEnd(body, count);
- }
- // search the doc
- var retRange = null;
- var selectionRange = null;
-
- if (!wrapped) {
- do {
- retRange = finder.Find(str, searchRange, startPt, endPt);
- var keepSearching = false;
- if (retRange) {
- var sc = retRange.startContainer;
- var ec = retRange.endContainer;
- var scp = sc.parentNode;
- var ecp = ec.parentNode;
- var sy1 = abs_point(scp).y;
- var ey2 = abs_point(ecp).y + ecp.offsetHeight;
-
- startPt = retRange.startContainer.ownerDocument.createRange();
- if (!dir) {
- startPt.setStart(retRange.startContainer, retRange.startOffset);
- startPt.setEnd(retRange.startContainer, retRange.startOffset);
- } else {
- startPt.setStart(retRange.endContainer, retRange.endOffset);
- startPt.setEnd(retRange.endContainer, retRange.endOffset);
- }
- // We want to find a match that is completely
- // visible, otherwise the view will scroll just a
- // bit to fit the selection in completely.
-// alert ("sy1: " + sy1 + " scry: " + gWin.scrollY);
-// alert ("ey2: " + ey2 + " bot: " + (gWin.scrollY + gWin.innerHeight));
- keepSearching = (dir && sy1 < gWin.scrollY)
- || (!dir && ey2 >= gWin.scrollY + gWin.innerHeight);
- }
- } while (retRange && keepSearching);
- } else {
- retRange = finder.Find(str, searchRange, startPt, endPt);
- }
-
- if (retRange) {
- setSelection(retRange);
- selectionRange = retRange.cloneRange();
- // highlightAllBut(str, retRange, color);
- } else {
-
- }
-
- return selectionRange;
- } catch(e) { alert('highlightFind:'+e); }
-}
-
-function clearHighlight()
-{
- gFindBar.highlightDoc();
- var win = window.content;
- var doc = win.document;
- if (!document)
- return;
-
- var elem = null;
- while ((elem = doc.getElementById("__vimperator-findbar-search-id"))) {
- var child = null;
- var docfrag = doc.createDocumentFragment();
- var next = elem.nextSibling;
- var parent = elem.parentNode;
- while ((child = elem.firstChild)) {
- docfrag.appendChild(child);
- }
- parent.removeChild(elem);
- parent.insertBefore(docfrag, next);
- }
-}
-
-/*
- * Finds the absolute X and Y co-ordinates of a given node from the top left of
- * the document
- *
- * Taken from conkeror utils.js
- */
-function abs_point (node) {
- var orig = node;
- var pt = {};
- try {
- pt.x = node.offsetLeft;
- pt.y = node.offsetTop;
-
- // Find imagemap's coordinates
- if (node.tagName == "AREA") {
- var coords = node.getAttribute("coords").split(",");
- pt.x += Number(coords[0]);
- pt.y += Number(coords[1]);
- }
-
- node = node.offsetParent;
-
- while (node.tagName != "BODY") {
- pt.x += node.offsetLeft;
- pt.y += node.offsetTop;
- node = node.offsetParent;
- }
- }
- catch (e) {
- // Ignore
- }
- return pt;
-}
-
-// Vimperator searcher
// make sure you only create this object when the "vimperator" object is ready
-//vimperator.search = new function()
+// vimperator.search = new function()
function Search() //{{{
{
var self = this; // needed for callbacks since "this" is the "vimperator" object in a callback
- this.gWin = null;
- this.gSelCtrl = null;
- this.gFindState = [];
+ var found = false; // true if the last search was successful
+ var backwards = false;
+ var lastsearch = ""; // keep track of the last searched string
+ var lastsearch_backwards = false; // like "backwards", but for the last search, so if you cancel a search with this is not set
// Event handlers for search - closure is needed
vimperator.registerCallback("change", vimperator.modes.SEARCH_FORWARD, function(command){ self.searchKeyPressed(command); });
vimperator.registerCallback("submit", vimperator.modes.SEARCH_FORWARD, function(command){ self.searchSubmitted(command); });
- vimperator.registerCallback("cancel", vimperator.modes.SEARCH_FORWARD, function(){ self.searchCancelled(); });
+ vimperator.registerCallback("cancel", vimperator.modes.SEARCH_FORWARD, function(){ self.searchCanceled(); });
+ // TODO: allow advanced modes in register/triggerCallback
+ vimperator.registerCallback("change", vimperator.modes.SEARCH_BACKWARD, function(command){ self.searchKeyPressed(command); });
+ vimperator.registerCallback("submit", vimperator.modes.SEARCH_BACKWARD, function(command){ self.searchSubmitted(command); });
+ vimperator.registerCallback("cancel", vimperator.modes.SEARCH_BACKWARD, function(){ self.searchCanceled(); });
-
- // Called when the search dialog is asked for. Sets up everything necessary
- // for this round of searching
- this.openSearchDialog = function()
+ // Called when the search dialog is asked for
+ // If you omit "mode", it will default to forward searching
+ this.openSearchDialog = function(mode)
{
- // Get a reference to the focused window if necessary
- if (this.gWin == null) this.gWin = document.commandDispatcher.focusedWindow;
-
- // Change the currently selected text to not be the attention colour
- // @todo: check what this REALLY does
- try {
- this.gSelCtrl = this.getFocusedSelCtrl();
- this.gSelCtrl.setDisplaySelection(Components.interfaces.nsISelectionController.SELECTION_ATTENTION);
- this.gSelCtrl.repaintSelection(Components.interfaces.nsISelectionController.SELECTION_NORMAL);
+ if (mode == vimperator.modes.SEARCH_BACKWARD)
+ {
+ vimperator.commandline.open('?', '', vimperator.modes.SEARCH_BACKWARD);
+ backwards = true;
}
- catch (e) {
- alert('Could not change the colour of the current selection:' + e);
+ else
+ {
+ vimperator.commandline.open('/', '', vimperator.modes.SEARCH_FORWARD);
+ backwards = false;
}
- // Initialize the state list for this attempt at searching
- var state = this.createInitialFindState();
- this.gFindState = [];
- this.gFindState.push(state);
- this.resumeFindState(state);
-
- vimperator.commandline.open('/', '', vimperator.modes.SEARCH_FORWARD);
+ // TODO: focus the top of the currently visible screen
}
- // Called when the current search needs to be repeated in the forward
- // direction
- // @todo will need re-jigging when reverse search comes in
- this.findNext = function() {
- this.find(this.lastFindState()["search-str"], true, this.lastFindState()["range"]);
- this.resumeFindState(this.lastFindState());
- // if there is still a search result
- if (this.lastFindState()["range"]) {
- if (this.lastFindState()["wrapped"]) {
- vimperator.echoerr("search hit BOTTOM, continuing at TOP");
- this.lastFindState()["wrapped"] = false;
- }
- else {
- // TODO: this could probably be done in a nicer way - perhaps
- // echoErr could not clobber all of this information somehow?
- vimperator.echo('/' + this.lastFindState()["search-str"]);
- }
- }
+ // Finds text in a page
+ // TODO: backwards seems impossible i fear :(
+ this.find = function(str, backwards)
+ {
+ const FIND_NORMAL = 0;
+ const FIND_TYPEAHEAD = 1;
+ const FIND_LINKS = 2;
+
+ found = getBrowser().fastFind.find(str, false) != Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND;
+
+ return found;
}
- // Called when the current search needs to be repeated in the backward
- // direction
- this.findPrevious = function() {
- this.find(this.lastFindState()["search-str"], false, this.lastFindState()["range"]);
- this.resumeFindState(this.lastFindState());
- // if there is still a search result
- if (this.lastFindState()["range"]) {
- if (this.lastFindState()["wrapped"]) {
- vimperator.echoerr("search hit TOP, continuing at BOTTOM");
- this.lastFindState()["wrapped"] = false;
- }
- else {
- vimperator.echo('/' + this.lastFindState()["search-str"]);
- }
+ // Called when the current search needs to be repeated
+ this.findAgain = function(reverse)
+ {
+ // this hack is needed to make n/N work with the correct string, if
+ // we typed /foo after the original search
+ if (getBrowser().fastFind.searchString != lastsearch)
+ {
+ this.clear();
+ this.find(lastsearch, false);
+ gFindBar.highlightDoc("yellow", "black", lastsearch);
}
+
+ var up = reverse ? !lastsearch_backwards : lastsearch_backwards;
+ var result;
+
+ if (up)
+ result = getBrowser().fastFind.findPrevious();
+ else
+ result = getBrowser().fastFind.findNext();
+
+ if (result == Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND)
+ vimperator.echoerr("E486: Pattern not found: " + lastsearch);
+ else if (result == Components.interfaces.nsITypeAheadFind.FIND_WRAPPED)
+ {
+ // hack needed, because wrapping causes a "scroll" event which clears
+ // our command line
+ setTimeout( function() {
+ if (up)
+ vimperator.echoerr("search hit TOP, continuing at BOTTOM");
+ else
+ vimperator.echoerr("search hit BOTTOM, continuing at TOP");
+ }, 10);
+ }
+ else // just clear the command line if something has been found
+ vimperator.echo("");
}
// Called when the user types a key in the search dialog. Triggers a find attempt
- this.searchKeyPressed = function(command) {
- if (command != "") {
- var str = vimperator.commandline.getCommand();
- this.find(str, true, this.lastFindState()["point"]);
- this.resumeFindState(this.lastFindState());
- }
- else {
- clearSelection();
- }
+ this.searchKeyPressed = function(command)
+ {
+ // TODO: check for 'incsearch'
+ var backward = vimperator.hasMode(vimperator.modes.SEARCH_BACKWARD);
+ this.find(command, backward);
}
// Called when the enter key is pressed to trigger a search
- this.searchSubmitted = function(command) {
- //removeMode(MODE_SEARCH);
+ this.searchSubmitted = function(command)
+ {
+ this.clear();
+ gFindBar.highlightDoc("yellow", "black", command);
+
+ // need to find again to draw the highlight of the current search
+ // result over the "highlight all" search results
+ // very hacky, but seem to work
+ setTimeout(function() { self.findAgain(false); }, 10);
+
+ lastsearch_backwards = backwards;
+ lastsearch = command;
+
vimperator.setMode(vimperator.modes.NORMAL);
- if (this.lastFindState()["range"] == null) {
- vimperator.echoerr("E492: Pattern not found: " + this.lastFindState()["search-str"]);
- }
+ vimperator.focusContent();
}
// Called when the search is cancelled - for example if someone presses
// escape while typing a search
- this.searchCancelled = function() {
+ this.searchCanceled = function()
+ {
//removeMode(MODE_SEARCH);
vimperator.setMode(vimperator.modes.NORMAL);
- clearSelection();
+ this.clear();
vimperator.focusContent();
}
-
- //
- // Helper methods
- //
-
- // Turn on the selection in all frames
- // @todo to tell the truth, I have no idea what this does
- this.getFocusedSelCtrl = function() {
- var ds = getBrowser().docShell;
- var dsEnum = ds.getDocShellEnumerator(Components.interfaces.nsIDocShellTreeItem.typeContent,
- Components.interfaces.nsIDocShell.ENUMERATE_FORWARDS);
- while (dsEnum.hasMoreElements()) {
- ds = dsEnum.getNext().QueryInterface(Components.interfaces.nsIDocShell);
- if (ds.hasFocus) {
- var display = ds.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
- .getInterface(Components.interfaces.nsISelectionDisplay);
- if (!display) return null;
- return display.QueryInterface(Components.interfaces.nsISelectionController);
- }
- }
-
- // One last try
- return getBrowser().docShell
- .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
- .getInterface(Components.interfaces.nsISelectionDisplay)
- .QueryInterface(Components.interfaces.nsISelectionController);
- }
-
- // Creates a default find state
- this.createInitialFindState = function() {
- var state = [];
- state["screenx"] = this.gWin.scrollX;
- state["screeny"] = this.gWin.scrollY;
- state["search-str"] = "";
- state["wrapped"] = false;
- state["point"] = null;
- state["range"] = document.createRange();
- state["selection"] = null;
- state["direction"] = true;
- return state;
- }
-
- // Given a find state, moves the browser to the way it should be in the
- // state - highlighting the correct thing and the screen scrolled to the
- // correct location
- this.resumeFindState = function(state) {
- if (state["selection"]) {
- setSelection(state["selection"]);
- }
- else {
- clearSelection();
- }
- this.gWin.scrollTo(state["screenx"], state["screeny"]);
- }
-
- // Retrieves the current find state that we're in
- // @todo rename to currentFindState?
- this.lastFindState = function() {
- return this.gFindState[this.gFindState.length - 1];
- }
-
- // Adds a find state to the stack of such states. This is done every time a find is successful
- this.addFindState = function(screenX, screenY, searchStr, wrapped, point, range, selection, direction) {
- var state = [];
- state["screenx"] = screenX;
- state["screeny"] = screenY;
- state["search-str"] = searchStr;
- state["wrapped"] = wrapped;
- state["point"] = point;
- state["range"] = range;
- state["selection"] = selection;
- state["direction"] = direction;
- this.gFindState.push(state);
- }
-
- // Finds text in a page
- this.find = function(str, dir, pt)
+ this.clear = function()
{
- var norecurse = arguments[3];
-
- var matchRange;
- clearHighlight();
-
- // Should we wrap this time?
- var wrapped = this.lastFindState()["wrapped"];
- var point = pt;
- if (this.lastFindState()["wrapped"] == false
- && this.lastFindState()["range"] == null
- && this.lastFindState()["search-str"] == str
- && this.lastFindState()["direction"] == dir) {
- wrapped = true;
- point = null;
- }
- gFindBar.highlightDoc('yellow', 'black', str);
- matchRange = highlightFind(str, "lightblue", wrapped, dir, point);
- if (matchRange == null) {
- // No more matches in this direction. So add the state and then find
- // again to wrap around. But only find again once to prevent infinite
- // recursion if an error occurs
- this.addFindState(this.gWin.scrollX, this.gWin.scrollY, str, wrapped, point,
- matchRange, this.lastFindState()["selection"], dir);
- if (!norecurse)
- this.find(str, dir, pt, true);
- }
- else {
- this.addFindState(this.gWin.scrollX, this.gWin.scrollY, str, wrapped,
- point, matchRange, matchRange, dir);
- }
+ gFindBar.highlightDoc();
}
+
} //}}}
-//// @TODO should be moved into commands.js
-//vimperator.commands.add(new Command(["noh[lsearch]"],
-// clearSelection,
-// {
-// short_help: "Clear the current selection"
-// }
-//));
-
// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/chrome/content/vimperator/mappings.js b/chrome/content/vimperator/mappings.js
index 7631aa19..61ad5388 100644
--- a/chrome/content/vimperator/mappings.js
+++ b/chrome/content/vimperator/mappings.js
@@ -938,27 +938,32 @@ function Mappings() //{{{
));
// search management
- addDefaultMap(new Map(vimperator.modes.NORMAL, ["g/"],
- function() { vimperator.search.openSearchDialog(); },
+ addDefaultMap(new Map(vimperator.modes.NORMAL, ["/"],
+ function() { vimperator.search.openSearchDialog(vimperator.modes.SEARCH_FORWARD); },
{
short_help: "Search forward for a pattern",
- help: "Buggy on many sites, use / if you want a reliable search!"
+ help: "TODO"
+ }
+ ));
+ addDefaultMap(new Map(vimperator.modes.NORMAL, ["?"],
+ function() { vimperator.search.openSearchDialog(vimperator.modes.SEARCH_BACKWARD); },
+ {
+ short_help: "Search backwards for a pattern",
+ help: "TODO"
}
));
addDefaultMap(new Map(vimperator.modes.NORMAL, ["n"],
- function() { vimperator.search.findNext(); },
+ function() { vimperator.search.findAgain(false); },
{
short_help: "Find next",
- help: "Repeat the last \"g/\" 1 time (until count is supported).
" +
- "NOTE: As \"g/\" is a little broken right now, use <F3> to go to the next search item of the \"/\" search for now."
+ help: "Repeat the last search 1 time (until count is supported)."
}
));
addDefaultMap(new Map(vimperator.modes.NORMAL, ["N"],
- function() { vimperator.search.findPrevious(); },
+ function() { vimperator.search.findAgain(true); },
{
short_help: "Find previous",
- help: "Repeat the last \"g/\" 1 time (until count is supported) in the opposite direction.
" +
- "NOTE: As \"g/\" is a little broken right now, use <S-F3> to go to the previous search item of the \"/\" search for now."
+ help: "Repeat the last search 1 time (until count is supported) in the opposite direction."
}
));
diff --git a/chrome/content/vimperator/options.js b/chrome/content/vimperator/options.js
index 8b018a22..89d874cc 100644
--- a/chrome/content/vimperator/options.js
+++ b/chrome/content/vimperator/options.js
@@ -415,7 +415,7 @@ function Options() //{{{
addOption(new Option(["hintstyle", "hs"], "string",
{
short_help: "CSS specification of unfocused hints appearance",
- default_value: "z-index:5000; font-family:monospace; font-size:12px; color:black; background-color:yellow; " +
+ default_value: "z-index:5000; font-family:monospace; font-size:12px; color:white; background-color:red; " +
"border-color:ButtonShadow; border-width:0px; border-style:solid; padding:0px 1px 0px 1px; position:absolute;"
}
));
diff --git a/chrome/content/vimperator/ui.js b/chrome/content/vimperator/ui.js
index 3fa02b6e..fd126578 100644
--- a/chrome/content/vimperator/ui.js
+++ b/chrome/content/vimperator/ui.js
@@ -528,8 +528,10 @@ function CommandLine() //{{{
// and blur the command line if there is no text left
if (command.length == 0)
{
- this.clear();
+ vimperator.triggerCallback("cancel", cur_extended_mode);
+ vimperator.setMode(old_mode, old_extended_mode);
vimperator.focusContent();
+ this.clear();
}
}
else // any other key
diff --git a/vimperator.vim b/vimperator.vim
index 57d56792..739487c6 100644
--- a/vimperator.vim
+++ b/vimperator.vim
@@ -18,11 +18,11 @@ syn match vimperatorComment +".*$+ contains=vimperatorTodo,@Spell
syn keyword vimperatorCommand addo[ns] ba[ck] bd[elete] bw[ipeout] bun[load] tabc[lose] beep bma[dd] bmd[el] bookm[arks] bm
\ b[uffer] buffers files ls delm[arks] downl[oads] dl ec[ho] echoe[rr] exe[cute] exu[sage] fo[rward] fw ha[rdcopy] h[elp]
- \ hist[ory] hs javas[cript] js mapc[lear] ma[rk] map marks no[remap] o[pen] e[dit] pc[lose] pref[erences] prefs q[uit]
- \ quita[ll] qa[ll] re[load] reloada[ll] res[tart] sav[eas] se[t] so[urce] st[op] tab tabl[ast] tabm[ove] tabn[ext] tn[ext]
- \ tabo[nly] tabopen t[open] tabnew tabe[dit] tabp[revious] tp[revious] tabN[ext] tN[ext] tabr[ewind] tabfir[st] u[ndo]
- \ qmarka[dd] qma[dd] qmarkd[el] qmd[el] qmarks qms unm[ap] ve[rsion] viu[sage] win[open] w[open] wine[dit] wqa[ll] wq
- \ xa[ll] zo[om] noh[ilight]
+ \ hist[ory] hs javas[cript] js mapc[lear] ma[rk] map marks noh[lsearch] no[remap] o[pen] e[dit] pc[lose] pref[erences]
+ \ prefs q[uit] quita[ll] qa[ll] re[load] reloada[ll] res[tart] sav[eas] se[t] so[urce] st[op] tab tabl[ast] tabm[ove]
+ \ tabn[ext] tn[ext] tabo[nly] tabopen t[open] tabnew tabe[dit] tabp[revious] tp[revious] tabN[ext] tN[ext] tabr[ewind]
+ \ tabfir[st] u[ndo] qmarka[dd] qma[dd] qmarkd[el] qmd[el] qmarks qms unm[ap] ve[rsion] viu[sage] win[open] w[open]
+ \ wine[dit] wqa[ll] wq xa[ll] zo[om]
\ contained
" FIXME