Firefox and Emacs
For me, there is NO difference between Firefox and Emacs. They provide useful APIs, nothing more.
Three years ago, I wrote Use firefox in Emacs way to demo how to convert Firefox into Emacs by Keynsail.
A year ago I published Hello Ivy-mode, bye Helm to prove how powerful Ivy-mode is by using its API ivy-read
.
Keysnail has similar javascript API prompt.selector
and it's as powerful as ivy-read
if not more powerful.
For example, you can insert below snippet into ~/.keysnail.js
and press ",hh" or "C-c C-h" to query browse history:
function searchHistory(evt, arg) {
function timeSince(now, date) {
var seconds = Math.floor((now - date) / 1000);
var interval = Math.floor(seconds / 31536000);
if (interval > 1) {
return interval + " years";
}
interval = Math.floor(seconds / 2592000);
if (interval > 1) {
return interval + " months";
}
interval = Math.floor(seconds / 86400);
if (interval > 1) {
return interval + " days";
}
interval = Math.floor(seconds / 3600);
if (interval > 1) {
return interval + " hours";
}
interval = Math.floor(seconds / 60);
if (interval > 1) {
return interval + " minutes";
}
return Math.floor(seconds) + " seconds";
}
function searchWithKeyword(q) {
var collection = (function() {
//search option
var options = PlacesUtils.history.getNewQueryOptions();
options.maxResults = 4096;
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
//options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_FRECENCY_DESCENDING;
options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
options.includeHidden = true;
//search query
var query = PlacesUtils.history.getNewQuery();
// read keyworld
if(q && q !== '') {
query.searchTerms = q;
}
var result = PlacesUtils.history.executeQuery(query, options);
var root = result.root;
var collection = [];
var now = new Date().getTime();
var siteNode;
root.containerOpen = true;
for (var i = 0; i < root.childCount; i++) {
// siteNode => nsINavHistoryResultNode
siteNode = root.getChild(i);
collection.push([siteNode.icon,siteNode.title,siteNode.uri, siteNode.time/1000]);
}
collection.sort(function(a, b) {
return b[3]-a[3];
});
// reformat the time
for (i = 0; i < collection.length; i++) {
collection[i][3] = timeSince(now, collection[i][3]) + ' ago';
}
root.containerOpen = false;
return collection;
})();
prompt.selector({
message : "Search history"+ (q && q !== ''? (' @'+q +':') : ':' ),
collection : collection,
flags : [ICON | IGNORE, 0, 0, 0],
header : ["Title", "Url", "Last visited"],
width : [30, 60, 10],
callback: function (i) {
if (i >= 0) {
openUILinkIn(collection[i][2], "tab");
}
},
onFinish: function() {
gBrowser.focus();
_content.focus();
}
});
}
prompt.finish(true);
prompt.read('Keyword to search history?', searchWithKeyword, null, null, null, 0, "history_search");
// searchWithKeyword('test');
}
key.setViewKey([',', 'h', 'h'], searchHistory, "Search history");
key.setGlobalKey(['C-c', 'C-h'], searchHistory, "Search history");
Here is my complete .keysnail.js.