conkeror: web browsing the emacs way





Web browsing is one of the few computer-based activities for which I usually
do not use emacs. Of course, there are of emacs-based browsers like w3m,
which is pretty good. But for the 21st-century web, a text-mode browser is a
bit limited. There are some efforts underway to integrate a graphical web
browser experience in emacs (e.g., using Xembed), but it will take a while
before that is ready.


The next best thing to web browsing with emacs, is a browser that is
inspired by emacs. Such a browser exists: it's called conkeror (not to be
confused with KDE's Konqueror). conkeror is a Mozilla-based browser that
brings an emacs-like experience to web browsing. I've been using it for more
than a year now as my primary browser, and I am quite happy with it.


Conkeror is a user-interface for the normal Mozilla/Firefox engine
(xulrunner); this means that all those websites that work with Firefox, work
just as well in conkeror, including things like ad-blockers, Java, Flash
etc. and many plug-ins. This is a very important point for me.


If you like emacs, you'll probably also like conkeror. For starters, it uses
many of the same key bindings – C-x C-f will open a url in a new buffer
(tab), C-x 5 2 will open a new window (frame), I can inspect a key-binding
with C-h k… and so on. Some of the single-key shortcuts are the same as
those in w3m, like g to go to a webpage, or B to go back. Conkeror
is fully keyboard-driven; it allows you do almost anything on the web without
using the mouse – it can overlay numbers on items in a webpage so you can
interact with them by their number. Of course, you can still use a mouse if
you want, too.


The conkeror wiki gives many more examples. It also discusses installation in
quite some detail, which makes life a bit easier for me :) Instead, I will
just list a couple of the customizations I have made and encourage you to try
for yourself.




configuration



Like emacs, conkeror is very configurable. The big difference is that
conkeror uses Javascript instead of Elisp for the configuration; however,
the concepts and naming should be familiar for emacs-users. Conkeror's
equivalent of ~/.emacs is ~/.conkerorrc. Below are some snippets from my
setup, that can hopefully help you to create your Perfect Browser ™; all
examples below are based on the latest development version of Conkeror, as
per end of November 2010.


First, some basics:


//allow for 'contrib' stuff
load_paths.unshift("chrome://conkeror-contrib/content/");

// teach me something whenever I start my browser
homepage = "http://en.wikipedia.org/wiki/Special:Random";

// give me new tabs; open buffers (tabs) in the background
require("new-tabs.js");
require("clicks-in-new-buffer.js");
clicks_in_new_buffer_target = OPEN_NEW_BUFFER_BACKGROUND;
clicks_in_new_buffer_button = 1; // midclick links in new buffers with

// auto completion in the minibuffer
minibuffer_auto_complete_default = true;
url_completion_use_history = true; // should work since bf05c87405
url_completion_use_bookmarks = true;





modeline customization



As in emacs, you can customize the modeline. Also in good emacs tradition,
this is far from intuitive…


require("mode-line.js");
// funky icons in the modeline
require("mode-line-buttons.js");
mode_line_add_buttons(standard_mode_line_buttons, true);

// we'd like to see the # of buffers being loaded
add_hook("mode_line_hook", mode_line_adder(loading_count_widget), true);
// we don't need a clock
remove_hook("mode_line_hook", mode_line_adder(clock_widget));






bookmarks



Plain-old bookmarks are easy to add with define_webjump – and you can just
bind them to a short string. You can then 'jump' to the corresponding website by
pressing g and then this short string. For example, to go to Emacs-Fu, you
could type g efu RET. No mousing around needed.


// some bookmarks
define_webjump("conk", "http://conkeror.org");
define_webjump("efu", "http://emacs-fu.blogspot.com");
define_webjump("lkml", "http://lkml.org");
define_webjump("ew", "http://emacswiki.org");
// ...






smart links



Smartlinks are just like normal bookmarks, which the one difference that
they contain an %s-parameter which will be replaced by whatever you type
after the name of the bookmark. Thus, g imdb grande bouffe RET would
take you to the IMDB-page about the movie La Grande Bouffe.


Some examples:


define_webjump("so",    "http://stackoverflow.com/search?q=%s");
define_webjump("yts", "http://www.youtube.com/results?search_query=%s&aq=f");
define_webjump("imbd", "http://www.imdb.com/find?s=all&q=%s");
// ...






integration with emacs



Another useful feature in conkeror is the ability to interact with Emacs
(or any other text editor), so you can use emacs for writing text in web
pages; for example, when you're using emacs-daemon (you should), you could
can add the below, and C-i will then take you to emacs whenever you are in
a text field in a web page.


editor_shell_command = "emacsclient -c";






adding your own functions



It's fairly easy to add your own functions; admittedly, I'm still at the
beginning stages with that, but it's not too hard to combine the internal
function, and assign them to key bindings. Some examples:


// copy url with C-c u
interactive("copy-url",
"Copy the current buffer's URL to the clipboard",
function(I) {
var text = I.window.buffers.current.document.location.href;
writeToClipboard(text);
I.window.minibuffer.message("copied: " + text);
}
);
define_key(default_global_keymap, "C-c u", "copy-url");


// reload conkerorrc with C-c r
interactive("reload-config", "reload conkerorrc",
function(I) {
load_rc();
I.window.minibuffer.message("config reloaded");
}
);
define_key(default_global_keymap, "C-c r", "reload-config");

It's not necessarily so easy to find the exact functions / objects you need
to accomplish what you want. There's a certain learning curve – just like
when using emacs.





integration with org-mode



The integration with emacs can go further than merely editing text fields
though; it's possible to integrate conkeror with org-mode in emacs; I
have the following in my .conkerorrc (this requires emacs-daemon), based
on the code in WOrg:


// org-protocol stuff
function org_capture (url, title, selection, window) {
var cmd_str =
'emacsclient \"org-protocol:/capture:/w/'+url+'/'+title+'/'+selection+'\"';
if (window != null) {
window.minibuffer.message('Issuing ' + cmd_str);
}
shell_command_blind(cmd_str);
}

interactive("org-capture", "Clip url, title, and selection to capture via org-protocol",
function (I) {
org_capture(encodeURIComponent(I.buffer.display_uri_string),
encodeURIComponent(I.buffer.document.title),
encodeURIComponent(I.buffer.top_frame.getSelection()),
I.window);
});
// capture with C-c c
define_key(content_buffer_normal_keymap, "C-c c", "org-capture");

Then, on the emacs-side (in your .emacs), you should have a capture
template for this; for example:


;; ;; the 'w' corresponds with the 'w' used before as in:
;; emacsclient \"org-protocol:/capture:/w/ [...]
(setq org-capture-templates
'(
("w" "" entry ;; 'w' for 'org-protocol'
(file+headline "www.org" "Notes")
"* %^{Title}\n\n Source: %u, %c\n\n %i")
;; other templates
))

Now, when in conkeror, you can select some text, push C-c c ('capture');
emacs will offer you to save this text, including a link to the source, the
date and so on, and saves it for later retrieval. I really love this
feature!






so…



These were just a couple of the many things you can do with conkeror;
there's so much potential here. I haven't discussed many of the other
powerful features, such as the page-specific modes, that give special
features to specific websites, be it GMail or Wikipedia.


I've been using this fine browser for a year or so now, and I really like
it. There are a few rough edges here and there, but it's quite amazing what
the small development team has accomplished. I heartily recommend it – for
web-browsing the emacs-way, there's simple no better alternative.


Finally, if you're using conkeror already, and have some clever tricks
you'd like to share, feel free to do so in the comments.


undo






One of the advantages that text-editors have over daily life is the ease of
undoing things. Emacs in particular has a powerful undo-system to return to
the previous state of things.



Undo can be activated by pressing C-x u or C-_; if you are more comfortable
with using C-z for undo (as is the standard in many non-Emacs environments),
you can of course add that key binding as well, by putting in your .emacs:




(global-set-key (kbd "C-z") 'undo)




This overrides the default of C-z triggering suspend-frame, which is not a
great loss for most people.



Emacs-undo has some nice features - for example, if you have selected some text
('marked a region'), the undo operation only applies to that area. At the same
time, however, the undo-model can be confusing: in emacs, undo is treated like
any other command, which means that undo can be applied even to… undo,
which is different from what most other editors do. Let me give an example – if
it's confusing or tedious then, well, that's what it is…



Suppose I type




hello
world




now I press C-_, and I get




hello




Now I type foo




hello
foo




And press C-_ C-_; and I get back:




hello
world




This is because we're 'undoing the undo' of adding the word 'world', and thus,
it reappears! When you try this in most other editors, it would result in




hello




because those editors completely forget about 'world' after it is undone.



So, emacs' model is strictly more powerful - but some (many? )people find it a
bit confusing, esp. when a series of 'undos' is interrupted by a 'do'.



If you prefer the model that many other editors use, you might be interested in
redo-mode, in particular in RedoPlus. Using that package, undo (or rather,
redo) follows a different model. In that model, redo is 'special': it's
not registered as a buffer change, and as such it's conceptually different
from the redo=undo-undo model that emacs uses by default. As seen above, you
actually lose some information in the process.



Yet another way to tackle the undo-problem is implemented by UndoTree: the
states of your buffer are seen as nodes in a tree, and you can freely move to
specific nodes. UndoTree is as powerful as the emacs system, yet easier to
understand. It can even visualize the tree of changes - and you can then by
clicking on a node go back to the corresponding buffer state.



Now, when using UndoTree, let's look at our example again:



We started with:




hello
world




then did C-_ (which removed 'world') and typed 'foo' to get:




hello
foo




Now press C-u again, and 'foo' disappear. Now we press C-x u
(undo-tree-visualize) and we get a buffer with:




  |
o
|
|
x
|
/ \
o o




and we can now visually move to any of the nodes, and our buffer is instantly
brought back. Cool! The two branches correspond to the states 'world' and 'foo'.
I have been undo-tree-mode for the last few weeks, and it works very well:
usually I don't even notice it, but when I need the extra power, it's there.



I am told that UndoTree is inspired by the way the vim-text editor does
this. Anyway, there is another very powerful feature in the vim undo-system
that would be nice to have in emacs to: time-based undo. In vim you can e.g. say
something like:




:earlier 5m




to go to the state of your buffer 5 minutes ago. That would be a nice addition
for undo-tree-mode!



Update Tavis Rudd notes that pressing t in undo-tree-visualizer-mode
(i.e.. what you see when your press C-x u) will give you timestamps instead of
o and x:




                  |
|
18:54:20
|
|
18:54:20
________|___
/ \
18:54:15 18:53:37
| |
| |
18:54:15 18:53:37
___|___ |
/ \ |
18:54:10 18:53:43 18:53:36





Followers

Popular Posts