An RSS/Atom newsreader that sucks less

Canto | Configuration


Old Docs. Current version here.
HOMENEWSFAQDOWNLOADGETTING STARTEDCONFIGSTYLEGITWEBBUG TRACKERCONTACT

This is where we'll go into the magic of ~/.canto/conf. This file is actually parsed and driven by the Python interpreter itself, so it's immensely powerful. It has the entirety of the Python language behind it, and allows for an incredible amount of flexibility.

If you've already gone through the basics, then you might be looking for Advanced Configuration. That's were all the neat hooks and filters are covered.

Example Config

This gives a fairly comprehensive view of the config. Everything that is not defined in it, is defined in canto.extra, which you can browse here

from canto.extra import *
import os

if os.getenv("TERM") == "linux":
    link_handler("elinks \"%u\"", text=True)
else:
    link_handler("iceweasel \"%u\"")

    # A dedicated image handler, that requires content
    # to be fetched for it.
    image_handler("xli \"%u\"", fetch=True)

    # A dedicated PDF handler (great for LtU)
    link_handler("evince \"%u\"", fetch=True, ext="pdf")

    # If we're in X, update xterm title
    # (Should work with most graphical terms)   
    select_hook = set_xterm_title
    end_hook = clear_xterm_title

def my_resize_hook(cfg):
    cfg.columns = cfg.width / 70

resize_hook = my_resize_hook

# Global filters, switch with '[' and ']'
filters=[None, show_unread]

# You can also setup keybinds to set the global filter
keys['a'] = set_filter(show_unread)

# Similarly you can set tag filters and keybinds
# switch with '{' and '}'

default_tag_filters([None, show_unread])
keys['b'] = set_tag_filter(show_unread)

# Tag sorts can also be set with a keybind
keys['s'] = set_tag_sort(by_alpha)
keys['d'] = set_tag_sort(reverse_sort(by_len))

# Keys can be single or lists of actions
# These keys kill the current reader, go to the next
# or prev unread item and start another reader

reader_keys["."] = ["destroy","next_unread","reader"]
reader_keys[","] = ["destroy","prev_unread","reader"]

# This sets the current item as read and automatically
# continues to the next item.

keys['x'] = ["just_read","next_item"]

# Searches can be bound to keybinds as well
keys['1'] = search(".*[Ll]inux.*", regex=True)
keys['2'] = search("Obama")

# And, of course keys can be unset.
keys['Q'] = None

# This makes the reader show links by default, rather
# than the default, toggling with 'l'
keys[' '] = ["reader","toggle_show_links"]

# A whole mess of feeds with tags, and without.
# A 'None' tag will be replaced with the feeds title
# The first tag is what is show at the top of each feed by default

add("http://rss.slashdot.org/slashdot/Slashdot", tags=[None, "news"])
add("http://osnews.com/files/recent.xml", tags=[None, "news"])
add("http://www.damninteresting.com/?feed=rss2")
add("http://reddit.com/.rss", tags=["Reddit","news"])
add("http://programming.reddit.com/.rss", tags=["Proggit", "news"])

# Username / Passwords are supported for feeds protected by
# Basic or Digest passwords

add("http://feedparser.org/docs/examples/digest_auth.xml", username="test",
        password="digest")

# Tags can work without configuration, or can be customized.
# This makes the "news" tag default to showing only unread stories
# and sorting by date.

add_tag("news", filters=[show_unread], sorts=[[by_date]])

# Finally, you can set the tags shown with the tags list,
# and rotate with '<' and '>' by default.

tags = [ None, ["news"], ["Reddit", "Proggit"]]

# None will be interpreted as the default set of tags, i.e. one
# per feed.

add()

add(URL,[tags=],[rate=],[keep=],[renderer=],[filter=],[username=],[password=])

add() is the most basic function of Canto's config, adding a feed to your reader.

Example:

add("http://rss.slashdot.org/slashdot/Slashdot", rate=10, keep=20)

In this example, Slashdot gets added to your feed list. It's updated every 10 minutes (default is 5), and only 20 stories will be stored on disk. Both keyword arguments (rate and keep) are optional, so

add("http://reddit.com/.rss")

Is also valid. Feeds that use basic or digest authentication can be fetched using the username and password variables. An easy way to determine whether a feed is using either of these types of authentication is to browse to the feed with your browser. If the browser pops up a box asking for your username and password (rather than taking you to a page to login to the site), then it's fetchable. For an example, browse to the URL in this example:

add("http://feedparser.org/docs/examples/digest_auth.xml", username="test",
        password="digest")

The last simple option for add are the tags. Tags are applied to every story inside of a feed. Tags are simply arbitrary strings that can be used to collect items and filter/sort (or any other operation that works on groups of items). By default a None tag corresponds to the name of the feed given in the XML, and if no tags are specified, then tags=[None] is assumed. If tags are set though, the first tag is considered the main tag, and is used as the tag name in log output and in the default GUI.

add("http://reddit.com/.rss", tags=["Reddit", "news"])
add("http://rss.slashdot.org/slashdot/Slashdot", tags=[None, "news"])

In the first add call, Reddit is added, but instead of using "reddit: what's new online" (the name of the feed given by the feed itself), just plain "Reddit" is used when printing messages or categorizing Reddit items. In the second add call, Slashdot is added using it's given name. Both feeds are tagged "news".

In addition to any tags specified, every item has the tag "*", so it's possible to view every single item in a single tag, which is neat for doing things like sorting over every item.

The state of each item functions as a tag as well, so "read", "marked" can be implemented as tags. However, anything that can be accomplished with those tags might be better accomplished with filters.

The renderer option is covered here. The filter option is used identically to the filters described here.

Scripts

As of 0.6.0, Canto includes the ability to run scripts similarly to Snownews' execurl functionality. To use this functionality, place the scripts in your script directory (default: ~/.canto/scripts/) and add a feed with "script:" as the prefix.

For example, if I wanted to run a script to make an RSS feed out of Slashdot polls called slashdotpolls, I would place that file in ~/.canto/scripts/ and add the following line to my configuration:

add("script:slashdotpolls -external")

Where -external is an argument to the script. Be Aware: the script must have execute permissions, or canto-fetch will not execute it. You can add these permissions with chmod +x <scriptfile>.

Integration

Feeds can automatically be appended to your config from the command line, using canto -r <URL> [-t maintag], like so:

canto -r "http://reddit.com/.rss" -t "Reddit"

Using this functionality from other applications is simple. For example, to allow Firefox to add feeds to your canto config directly, you can "open" it with this simple script

#!/bin/sh
canto --url ${1/feed:/http:}

Make sure this script is executable by chmod +x <script> before you try it. Thanks to Ypsy for the script.

add_tag()

add_tag("name", [filters=],[sorts=])

add_tag is used to specify the attributes of tags. It's not necessary to add every tag that you use, as tags are all generated on-the-fly, but any tag that you want to have special attributes must be added. This includes the tags defined by feeds.

add_tag("Reddit", filters=[show_unread])
add_tag("news", sorts=[by_date])

change_feed()

change_feed(URL, [tags=],[rate=],[keep=],[renderer=],[filter=],[username=],[password=])

change_feed acts identically to add, but (as you would imagine) changes already added feeds. This is intended to add attributes to feeds added from other sources (like source_urls and source_opml) where these options aren't included in the input data.

source_opml()

source_opml("path", [append=True/False])

source_opml allows you to add feeds from an opml file at run time, rather than permanently. If you're interested in permanently adding or exporting your feeds with OPML, use canto -i and canto -o to import and export, respectively.

Example:

source_opml("/home/myuser/feeds.opml")

That append option determines whether the feeds added will be appended to your config file. If true, they will be added in the same manner as canto -i. Note that this will be appended every time the config is executed, so only use it if you're sure you want to add the add_feed statements to your config.

source_urls()

source_urls("path", [append=True/False])

source_urls works similarly to source_opml, except it generates add_feed statements from a newline delimited list of URLs.

Setting defaults

default_rate(rate)

default_keep(keep)

default_renderer(renderer)

default_tag_filters([filters...])

default_tag_sorts([[sorts],[sorts]])

The functions set the default rate in minutes and number of stories to keep for each feed added after the call. Both of these can be called at any point, and will not change previously entered feeds.

Example:

# These are actually Canto's defaults.
default_rate(5)
default_keep(40)

Content Handlers

link_handler(path, [text=],[fetch=],[ext=])

image_handler(path, [text=],[fetch=],[ext=])

link_handler handles content that's contained in <a> tags, while image_handler handles <img> content. The path argument is the path to the binary, with "%u" in place of the URL. text should be set to True if Canto should wait for the program (like a text-browser), and fetch should be set to True if the content must be fetched (if your program can only open local files).

The ext argument can be used to associate a particular handler only with links ending with a certain string.

Example:

# Your default link handlers
link_handler("firefox \"%u\"")

# xli can't open internet URLs
image_handler("xli \"%u\"", fetch=True)

# dedicated PDF handler
link_handler("evince \"%u\"", fetch=True, ext="pdf")

# text-browser
link_handler("elinks \"%u\"", text=True)

Reader positioning

reader_orientation=["top"|"bottom"|"left"|"right"|None]

reader_lines = number

If you don't like the reader floating over your list of items, then you can dedicate a certain amount of space to it. Set reader_orientation to "top", "bottom", "left", or "right" of the list. None is the default behavior, floating over the list.

reader_lines can increase the dedicated space, the minimum is 3 lines because any smaller and the default theme ceases to behave well, but it's practically unreadable anyway, so no worries.

Simple Example:

reader_orientation = "top"
reader_lines = 10

Now, you'll have 10 lines of dedicated space for the reader at the top of the screen, and your list of items underneath. A more flexible way to do this is to use a resize_hook to dedicate a certain percentage of the screen to the reader

def resize_hook (cfg):
    cfg.reader_orientation = "left"
    cfg.reader_lines = cfg.width / 2
    cfg.columns = (cfg.width / 2) / 50

This will set half of the screen to the left as dedicated space for the reader, and try to divide the rest into columns of width 50. resize_hook is covered with the rest of the hooks.

keys

keys["somekey"] = str, list of strings, function, list of functions

reader_keys["somekey"] = str, list of strings, function, list of functions

Canto has two main GUI elements. The main view, which lists the headlines, and the reader, which gives you more details on a particular story. Each of these views has a different set of possible keybinds.

The format of somekey follows the convention of C- for Ctrl, and M- for meta (usu. Alt). So, to bind Ctrl-Alt-J to a function somekey would be C-M-j, or M-C-j (order doesn't matter). In addition, more complex non-printable characters are looked up in the Python curses module. You can find a list of curses keys here, which is the manpage for getch.

Also note that multiple keys can be bound to a single function, and multiple functions can be assigned to a single key. If you wish to unbind a key, set it to None.

The functions you can bind to are:

Main view keys

Name Function Default Binding
help Shows the man page (has all of these bindings listed). h
next_item Move to the next item. KEY_DOWN / j
prev_item Move to the previous item. KEY_UP / k
next_tag Move to the next feed/group of items KEY_NPAGE
prev_tag Move to the previous feed/group of items. KEY_PPAGE
just_read Mark current story read and nothing else. KEY_RIGHT
just_unread Mark current story unread and nothing else. KEY_LEFT
goto Open the current story in your browser. g
inline_search Mark all stories matching a search. f
next_mark Go to the next marked story. n
prev_mark Go to the previous marked story. p
next_unread Go to the next unread story. .
prev_unread Go to the previous unread story. ,
reader Open the reader. Space
toggle_collapse_tag Collapse/Show a feed/group of items. c
set_collapse_all Collapse on all feeds/groups. C
unset_collapse_all Uncollapse all feeds/groups. V
toggle_mark Mark/unmark an item. m
all_unmarked Unmark all items M
tag_read Set all stories in a feed/group read. r
all_read Set all stories read. R
tag_unread Set all stories in a feed/group unread. u
all_unread Set all stories unread. U
force_update Reread stories from disk. C-r
refresh Redraw the screen. C-l
quit Quit Canto. q
next_filter Apply next global filter. ]
prev_filter Apply previous global filter ]
next_tag_filter Apply next tag filter (from filters) }
prev_tag_filter Apply previous feed filter {
prev_tagset Show previous set of tags <
next_tagset Show next set of tags >
goto_reltag Goto the nth visible tag (filter aware) ;
goto_tag Goto the nth tag (filter unaware) :
switch Switch focus to next gui item. TAB

Reader keys

Name Function Default Binding
scroll_down Scrolls, if there's more text. KEY_DOWN / j
scroll_up Scroll up, if not at the top. KEY_UP / k
page_down Page down. KEY_NPAGE
page_up Page Up. KEY_PPAGE
["destroy","next_item","reader"] Goto the next story without closing the reader. n
["destroy","prev_item","reader"] Goto the previous story without closing the reader. p
goto Go to a specific link listed inside the item text. g
toggle_show_links Show/hide the list of links at the bottom of the reader. l
switch Change focus to next gui item TAB
quit Quit space

Examples:

Set z in the main screen to open the story's link in a browser.

keys["z"] = "goto"

Set Ctrl-Alt-F1 to help.

keys["C-M-KEY_F1"] = "help"

Set 'j' to scroll up in the reader.

reader_keys["j"] = "scroll_up"

Set 'x' to set current item read and move to the next item.

keys["x"] = ["just_read","next_item"]

Advanced

There are a handful of other configuration options that you can use.

Canto has many options that allow you to change (radically, I might add) the way that Canto draws the screen, and (a little more safely) change the default colors used to display. These are covered in detail on the styling page.

Filters are covered here

Hooks are covered here.

Sorting feeds arbitrarily is covered here.

As are a lot of other goodies, like writing your own arbitrary keybinds.

Deprecated config options

Canto 0.6.0 deprecated a number of configuration options. browser and text_browser are replaced with the much more flexible and robust link_handler. Canto will still interpret these options with only a warning.

add_feed has been replaced with add and add_tag. Canto will interpret add_feed still with a warning, but will ignore all extra options.

All of these configuration options will disappear from Canto in the near future, so please update your configs.

Send all bug reports to canto-reader [at] codezen [dot] org
Or come to discuss in #canto on irc.freenode.net