NN(1)

✨ NN(1) ✨

okay bestie, listen. this is the manual page for nn, and it lives in General Commands Manual land, but honestly it's the main character of your Usenet era. it's long, it's iconic, and we're doing it properly 💅


🌸 NAME 🌸

nn — efficient net news interface (No News is good news)

no cap, that's the actual tagline. iconic.


🦋 SYNOPSIS 🦋

nn [ options ] [ newsgroup  |  +folder  |  file ]...
nn -g [ -r ]
nn -a0 [ newsgroup ]...

💖 DESCRIPTION 💖

okay so. Net news is this world-wide information exchange service, right? it covers approximately every topic in science and in everyday life, and the topics get organized into news groups. and here's the slay part: these groups are open for everybody to post articles on whatever subject the group is about. everybody. community. we love that for us.

nn is a point-and-shoot net news interface program — or a news reader, for short. and no, it is not to be confused with the human news reader, don't embarrass yourself 🙈. when you use nn, you get to decide which of the many news groups you're actually interested in, and you can unsubscribe from the ones that don't interest you. and bestie, nn will let you read the new (and old!) articles in every group you subscribe to, using a menu based article selection that happens before you read the articles themselves.

when a news group is entered, nn locates all the presently unread articles in that group and extracts their sender, subject, and other relevant info. then it rearranges, sorts, and marks all of that in various ways so it looks pleasant when it hits your screen. it's giving curated.

and it does this very quickly, because nn uses the NOV database via the NNTP XOVER command. ⚡

the news server you use can be overridden two ways:

  • set the environment variable $NNTPSERVER to the name of the system, like news.newserver.com
  • set the variable nntp-server as "nntp-server=news.some.domain" — and heads up, this one works on the command line only, because it gets looked at before the init file 👀

if you use multiple servers, you probably want to set the nn-directory and newsrc variables on the command line to alternate names as well, since some of the data files are server dependent. multi-server girlies, this is for you.

if you're on a slow tcp link (think ppp over a modem) and you're using NNTP, go read the NOTES section at the end of this manual. it's there for a reason, babes.


when the article menu appears on your screen, nn is in a mode called selection mode. in this mode, the articles that seem interesting can be selected with single keystrokes — using the keys a-z and 0-9. when you've selected every interesting article among the ones currently displayed, you hit the space bar, which sends nn straight into reading mode.

in reading mode, each of the selected articles gets presented to you. you use the space bar to go on to the next page of the current article, or to the next article. and obviously there's a whole menu of commands to scroll text up and down, skip to the next article, respond to an article, decrypt an article, and so on. we have range 🫶

when all the selected articles in the current group have been read, the last hit on the space bar makes nn continue to the next group with unread articles, and enter selection mode on that group. it just. keeps going. perpetual motion machine behavior.


🎀 FREQUENTLY USED OPTIONS 🎀

nn accepts a lot of command line options, but this section only covers the frequently used ones. the rest are chilling in the section on Command Line Options toward the end of this manual.

also! options can be set permanently by putting the appropriate variable settings in the init file described later. set it once, forget it forever, that's the dream.

so, the frequently used command line options are:

  • -a0 — Catch up on unread articles and groups. go see the section "Catch up" below.
  • -g — Prompt for the name of a news group or folder to be entered (with completion). the completion is the good part, trust.
  • -r — Used with -g to repeatedly prompt for groups to enter.
  • -lN — Print only the first N lines of the first page of each article before prompting to continue. super useful on slow terminals and modem lines, so you can peep the first few lines of longer articles before committing.
  • -sWORD — Collect only articles which contain the string WORD in their subject (case is ignored). this is normally combined with the -x and -m options to find all articles on a specific subject.
  • -s/regexp — Collect only articles whose subject matches the regular expression regexp. also normally combined with the -x and -m options to find all articles on a specific subject.
  • -nWORD or -n/regexp — Same as -s except that it matches on the sender's name instead of the article's subject. normally combined with the -x and -m options to find all articles from a specific author. and listen: it cannot be mixed with the -s option! pick a lane 💀
  • -i — Normally searches with -n and -s are case independent. using this option, the case becomes significant. uppercase girlies rise.
  • -m — Merge all articles into one meta group instead of showing them one group at a time. this is normally used together with the -x and -s options so all the articles on a specific subject land on a single menu (that's for when you don't care which group they belong to). and important: when -m is used, no articles will be marked as read.
  • -x[N] — Present (or scan) all (or the last N) unread as well as read articles. when this option is used, nn will never mark unread articles as read (i.e. .newsrc is not updated).
  • -X — Read/scan unsubscribed groups also. most useful when you're looking for a specific subject across all groups, e.g.
nn -mxX -sSubject all
  • news.group or file or +folder — If none of these arguments are given, all subscribed news groups will be used. otherwise, only the specified news groups and/or files will be collected and presented.

when specifying a news group, the following meta notation can be used:

  • if the news group ends with a . (or .all), all subgroups of the news group will be collected, e.g.
comp.sources.
  • if a news group starts with a . (or all.), all the matching subgroups will be collected, e.g.
.sources.unix
  • the argument all identifies all (subscribed) news groups.

💅 COMMAND INPUT 💅

in general, nn commands consist of one or two key-strokes, and nn reacts instantly to the commands you give it. you don't have to hit return after each command — except where it explicitly says so. instant gratification, periodt.

some commands have more serious effects than others, so nn will ask you to confirm. you confirm by hitting the y key, and you reject by hitting the n key. some trivial requests can also be confirmed simply by hitting space. for example: to confirm the creation of a save file, just hit space — but if one or more directories also have to be created, you must enter y. levels to it.

a lot of commands will require you to enter a line of text, like a file name or a shell command. if you enter space as the first character on a line, the line gets filled with a default value (if one is defined). for example, the default value for a file name is the last file name you entered, and the default shell command is your previous shell command. and you can edit that default value just like directly typed text, using these editing commands. quick note: the erase, kill, and interrupt keys are the keys defined by your current tty settings. and on systems without job control, the suspend key will be control-Z, while it's the current suspend character on systems with job control.

  • erase — Delete the last character on the line.
  • delete-word (normally ^W) — Delete the last word or component of the input.
  • kill — Delete all characters on the line.
  • interrupt and control-G — Cancel the command which needs the input.
  • suspend — Suspend nn if supported by the system. otherwise, spawn an interactive shell.
  • return — Terminate the line, and continue with the command.

Related variables: erase-key, flow-control, flush-typeahead, help-key, kill-key, word-key.


🌈 BASIC COMMANDS 🌈

there are numerous commands in nn, and most of them can be invoked with a single keystroke. the descriptions in this manual are based on the standard bindings of the commands to the keys, but you can totally customize these using the map command described later. for each of the keystroke commands described in this manual, the corresponding command name will also be shown in curly braces, e.g. {command}.

the following commands work in both selection mode and reading mode. and remember the notation: ^X means control X.

  • ? {help} — Help. gives you a one page overview of the commands available in the current mode.
  • ^L {redraw} — Redraw screen.
  • ^R {redraw} — Redraw screen (Same as ^L).
  • ^P {message} — Repeat the last message shown on the message line. the command can be repeated to successively show previous messages (the maximum number of saved messages is controlled via the message-history variable).
  • ! {shell} — Shell escape. the user is prompted for a command which is executed by your favorite shell (see the shell variable). shell escapes are described in detail later on.
  • Q {quit} — Quit nn. when you use this command, you neither lose unread articles in the current group nor the selections you might have made (unless the articles are expired in the meantime, of course). bestie-safe quitting 💖
  • V {version} — Print release and version information.
  • : command {command} — Execute the command by name. this form can be used to invoke any of nn's commands, including those which cannot be bound to a key (such as :coredump), or those which are not bound to a key by default (such as post and unshar).

Related and basic variables: backup, backup-suffix, confirm-auto-quit, expert, mail, message-history, new-group-action, newsrc, quick-count.

🌸 SELECTION MODE 🌸

okay so bestie, when you're in selection mode, your screen is literally split into four iconic zones: the header line up top showing the news group name and how many articles there are, the menu lines in the middle (one article per line, so organized ✨), the prompt line where you type your commands, and the message line where nn drops little messages for you. 💅

Each menu line starts with an article id — a unique letter (or a digit if your screen can show more than 26 menu lines, fancy). To select an article for reading, you just type its id, and boom, the menu line gets high-lighted to show it's selected. When you've picked all the interesting ones on this menu, you hit space. Simple.

If there are more articles in the current group than fit on one screenful, you get the next portion to choose from. Once you've had the chance to select among all the articles in the group, hitting space takes you into reading mode. 👑

If you didn't select any articles in the current group, hitting space enters selection mode on the next news group — or exits nn if this was the last group with unread articles. So you can literally go through ALL unread articles (without reading a single one) just by hitting space a few times. no cap.

The articles show up on the menu in one of these layouts:

0:     x Name.........  Subject.............. +123

1:     x Name.........   123  Subject..............

2:     x 123  Subject...................................

3:     x Subject...........................................

4:     x    Subject........................................

Here x is the letter or digit you type to select the article, Name is the sender's real name (or the mail address if the real name can't be found), Subject is what's in the "Subject:" line, and 123 is the number of lines in the article.

Layout 0 and 1 are just two ways to show the same info. Layout 2 and 3 are for groups with super long subject lines, like comp.sources. Layout 4 is a hybrid of 1 and 3 — it normally uses layout 1, but for menu lines where the subject is longer than the space available in layout 1, it switches to layout 3 (with a little indentation). So flexible. ✨

Layout 1 is the default. You can pick a different menu line layout with the -L option or by setting the layout variable. Once nn is running, you can change it anytime with the " key {layout}. 🎀

The Name is limited to 16 characters, and to squeeze the most out of that space, nn does a series of simplifications — like turning first names into initials, stripping domain names from mail addresses (if the real name isn't found), etc. It does a good job, but some people on the net put weird stuff in the From: field (or actually in their password file) which makes nn produce quite cryptic, and sometimes funny, "names". 😭

On a usual 80-column terminal, the Subject is limited to about 60 characters (75 in layout 3), so it's only an approximation of the actual subject line, which may be much longer. To make the most of that space, Re: prefixes (in various forms) are recognized and replaced by a single > character (see the re-layout variable).

Since articles are sorted by subject, two or more adjacent articles may share the same subject (ignoring any >'s). In that case, only the first article shows the subject; the rest just show the > character in the subject field (or a - if there's no > at the beginning of the line). So a typical menu only shows each subject once — saving you a lot of scanning time. 👑

If consolidated menus (see the section below) are enabled, adjacent articles sharing the same subject get shown with a single line on the menu corresponding to the first of those articles. The number of articles with the same subject appears as a bracketed number in front of the subject, like with layout 1:

x Name.........   123  [4] Subject..............

For more deets, see the section on consolidated menus below.

Related variables: collapse-subject, columns, confirm-entry, confirm-entry-limit, entry-report-limit, fsort, kill, layout, limit, lines, long-menu, re-layout, repeat, slow-mode, sort, sort-mode, split, subject-match-limit, subject-match-offset, subject-match-parts, subject-match-minimum.


💖 ARTICLE ATTRIBUTES 💖

While nn is running and between invocations, nn associates an attribute with each article on your system. These attributes help tell apart read vs unread articles, selected articles, articles marked for later treatment, etc. Depending on how nn is configured, these attributes can be saved between invocations, or some may only be used while nn is running. 👀

The attribute shows up on the menu either as a single character following the article id, or by high-lighting the menu line — depends on the attribute and what your terminal can do. You can also change the attributes to your own taste (see the attributes variable). 🎀

You can change an article's attribute explicitly with the selection mode commands described below, or it'll change automatically — like when you've read or saved a selected article. If a command may change any article attributes, it'll be noted in the command's description. The attribute descriptions below only mention the most important commands that may set (or preserve) the attribute.

The following attributes may be associated with an article:

  • read — Menu attribute . — means the article has been read or saved. When you leave the group, these articles get marked permanently read, and they won't show up the next time you enter the group.
  • seen — Menu attribute , — means the article is unread, but it has been presented on a menu. Depending on how nn is configured, these articles will automatically be marked read when you leave the group, they may remain seen, or they may just be unread the next time you enter the group (see the auto-junk-seen, confirm-junk-seen, and retain-seen-status variables). Only the commands continue (space) and read-skip (X) will mark unread articles on the current (or all) menu pages as seen when they're used. Other commands that scroll through the menu pages or enter reading mode will let unread articles remain unread.
  • unread — Menu attribute — means an unread article. These articles were unread when you entered the group, and they may remain unread when you leave the group, unless they've been marked seen by the command you used to leave the group or enter reading mode.
  • selected — Menu line high-lighted (or menu attribute *) — means you've selected the article. If you leave the group, the selected articles will remain selected the next time you enter the group. When you've read a selected article, the attribute automatically changes to read.
  • auto-selected — These articles look exactly like selected articles on the menu. The only difference is that they were selected automatically via the auto-selection facility rather than manually by you. Very few commands differentiate between these attributes, and if they do, it's explicitly stated in this manual. The main difference is that these articles are only marked as unread when you leave the group (supposing they'll also be auto-selected the next time the group is entered). This simplifies the house-keeping between invocations of nn.
  • leave — Menu attribute + — means the article is marked for later treatment by the leave-article (l) command. These articles may be selected (on demand) when you've read all selected articles in a group. However, if you don't select them immediately, they're stored as the leave-next attribute described below.
  • leave-next — Menu attribute = — means the article is marked for later treatment by the leave-next (L) command. This is a permanent attribute, which will remain on the article until you either read the article, change the attribute, or it expires. So assigning this attribute effectively keeps it unread until you do something. If the variable select-leave-next is set, nn will ask whether these articles should be selected on entry to a group (but naturally, doing so will change the leave-next attribute to select).
  • cancelled — Menu attribute # — means the article has been cancelled. This is mainly useful when tidying a folder; it's set by the cancel (C) command, and can be cleared by any command that changes attributes, e.g. you can select and deselect the article.
  • killed — Menu attribute ! — means the article has been killed (e.g. by the K {kill-select} command). Killed articles are immediately removed from the menu, so you shouldn't normally see articles with this attribute. If you do, report it as a bug! 🐛

The attributes are saved in two files: .newsrc (read articles) and .nn/select (other attributes). Plain unread articles are saved by not occurring in either of these files. Both files are described in more detail later on.

Related variables: attributes, auto-junk-seen, confirm-junk-seen, retain-seen-status, select-leave-next.

🫶 More on the toggle thing 🫶

Most of the commands that select articles work as toggles. If the article isn't already selected, it flips the selected attribute on the article(s), independent of whatever the previous attribute was. Otherwise the article(s) get deselected and marked unread. Which means — lowkey iconic loophole — you can mark any article unread just by selecting it and then deselecting it 💅

While you're selecting, the cursor normally sits on the article right after the last one whose attribute was changed (at the very start, that's the first article). That article under the cursor is called the current article, and every command below works relative to the current article and where the cursor is 👑

🎀 Selecting articles

  • abc...z 01..9 {article N} — selects or deselects the article with that identification letter or digit. The following article becomes the current article. And if the variable auto-select-subject is set? Every article with the same subject as the one you picked gets selected too 😌
  • . {select} — select or deselect the current article and move the cursor to the next article.
  • , {line+1} — move the cursor to the next article. The down arrow does this too ⬇️
  • / {line-1} — move the cursor to the previous article. Up arrow also works ⬆️
  • * {select-subject} — select or deselect all articles with the same subject as the current article. It'll work across several menu pages if it has to 🦋
  • -x {select-range} — select or deselect the range of articles between the current article and the article specified by x. So like, typing e-k selects everything from e to k. so satisfying 💅

🌈 Whole-page and whole-group energy

The following commands may change the attributes on all articles on the current menu page, or on all articles on all menu pages.

  • @ {select-invert} — reverse selections. Every selected article on the current page gets deselected, and vice-versa. (the manpage's own tip: use the find command to select all articles 🫶)
  • ~ {unselect-all} — deselect all the auto-selected articles in the group (this works across all menu pages). If you execute the command twice, the selected articles will also be deselected.
  • + {select-auto} — perform the auto-selections in the group (peep the section on "auto kill/select" below 👀).
  • = {find} — prompts you for a regular expression, and selects all articles on the menu (all pages!) that match that regular expression. Depending on the variable select-on-sender, matching is performed against the subject (that's the default) or the sender of the articles. An empty answer (= return) will reuse the previous expression. Example: the command = . return will select all articles in the group 🔥
  • J {junk-articles} — the versatile icon of this whole menu. Does all sorts of attribute changes, either on individual articles, all articles on the current menu page, all articles with a specific attribute, or all available articles. To get at every function of this command you may have to hit the J key up to four times, looping through different one-line menus. The full functionality of the junk-articles command is described in its own section below 👑
  • L {leave-next} — a specialized version of the generic J {junk-articles} command, setting the leave-next attribute on a subset of the articles on the menu. It's described further below too ✨

🧚 Paging through the group

The following commands move between the pages belonging to the same news group when there are more articles than will fit on a single page. These commands will not change any article attributes 🚫

  • > {page+1} — go to the next menu page.
  • < {page-1} — go to the previous menu page, or to the last menu page if you're on the first menu page.
  • $ {page=$} — go to the last menu page.
  • ^ {page=1} — go to the first menu page.

💜 Reading mode + group hopping

The following commands are used to enter reading mode for the selected articles, and to move between news groups (while you're in selection mode). They may change article attributes if noted below.

  • space {continue} — continue to the next menu page, or, if you're on the last menu page, read the selected articles. If no articles have been selected, continue to the next news group. The unread articles on the current menu page will automatically be marked seen 😬
  • return {continue-no-mark} — identical to the continue command, except the unread articles on the current menu page stay unread. (The newline key has the same effect.)
  • Z {read-return} — enter reading mode immediately with the currently selected articles. When all articles have been read, you return to selection mode in the current group. It'll mark selected articles read as they are read, but unread articles are not normally changed (this can be controlled with the variable marked-by-read-return).
  • X {read-skip} — mark all unmarked articles seen on all menu pages (or the pages defined by the marked-by-read-skip variable), and enter reading mode immediately with the currently selected articles. As the selected articles are read, they get marked read. When all selected articles have been read, nn enters selection mode in the next news group. And when no articles are selected, it goes directly to the next group. This is the move for skipping every article in a huge news group without having to go through all the menu pages 🔥
  • N {next-group} — go forward to the next group in the presentation sequence. If the variable marked-by-next-group is set, articles on the menu can optionally be marked seen.
  • P {previous} — go back to the previous group. This command will enter selection mode on the last active group (two P commands in sequence will bring you to the current group). If there are still some unread articles in the group, only those articles will be shown. Otherwise, all the articles that were unread when nn was invoked will be shown, marked with the read attribute (which can be changed as usual).

Wait, quick note before the N/P part above — okay so, if you don't wanna read the current group right now but you do wanna keep it for later, these are the commands that will only mark seen and read articles as read. Currently selected articles will still be selected the next time you enter the group. None of these commands will change any attributes themselves (by default). 💜


As described in the "Article Attributes" section, the read and seen articles will normally be marked read when you leave the group, and these articles are not shown the next time you enter the group.

kk now the lore: in all releases prior to release 6.4, it was impossible to have individual articles in a group marked unread when you left a group, and the default behaviour of release 6.4 onwards will closely match the traditional behaviour. Which means the seen and read articles are treated alike for most practical purposes with the default variable settings 🫠

If you don't like nn silently marking the seen articles read, you can set the variable confirm-junk-seen to get nn to prompt you for confirmation before doing this, or you can unset the variable auto-junk-seen to simply keep the seen articles for the next time you enter the group. You then have to use the J {junk-articles} to mark articles read.

Using return {continue-no-mark} will also let you keep articles unread rather than marking them seen when scrolling through the menu pages and entering reading mode. If that's your preferred reading style, you can remap space to this command ✨

Related variables:

  • auto-junk-seen
  • auto-preview-mode
  • auto-select-subject
  • case-fold-search
  • confirm-auto-quit
  • confirm-entry
  • confirm-junk-seen
  • marked-by-next-group
  • marked-by-read-return
  • marked-by-read-skip
  • retain-seen-status
  • select-on-sender

💖 CONSOLIDATED MENUS 💖

okay so bestie, listen — normally nn gives every single article its own lil menu line, right? which is fine and cute until you get a zillion articles with the exact same subject and your menu page is basically just five different subjects being repeated at you over and over. NOT the vibe. 🙈 so if you set the variable consolidated-menu, nn will operate with consolidated menus, meaning each subject shows up on the menu exactly once. obsessed.

When consolidated menus are on, nn works with two kinds of subjects: open and closed.

An open subject is a subject shown the traditional way — one whole menu line for each article that has that subject. Which like, lowkey means that when you're not using consolidated menus, all subjects are open. that's the default, periodt.

A closed subject is a multi-article subject presented as a single menu line. That line is just the normal menu line for the first (oldest) article with that subject, except the subject field gets annotated with a bracketed number showing how many articles share that subject, like:

a Kim F. Storm     12  [4] Future plans for nn
b.Kim F. Storm     43  [3] More plans for nn

so in this example there are four unread articles with subject a, the first one posted by me, and it has 12 lines. The rest of the articles are hidden and only show up if you ask. and the '.' marker on subject b? that's telling you all three articles inside that subject have been read (or seen). queen behavior honestly. 👑

To select (or deselect) ALL the articles inside a closed subject, you literally just select the article shown on the menu — it will automatically select (or deselect) the rest for you (see auto-select-closed). And when every unread article within a closed subject is selected, that menu line gets high-lighted. slay. ✨

If you wanna look at the individual articles in a subject (maybe to select them one by one, main character energy), you can open the subject with these commands:

  • (x — Open subject x on menu.
  • (( — Open current subject.

And when you're done viewing the opened subject, you can close it right back up with:

  • )x — Close subject x on menu (x is any article with the subject).
  • )) — Close current subject.

In the basic layout of the menu line for a closed subject like the one up there, ALL articles in the closed subject are supposed to be one of these:

  • unread — the menu line is not high-lighted.
  • selected — menu line is fully high-lighted (if all UNREAD are selected).
  • read/seen — there's a '.' (read attribute) following the article id.

And if none of those cases apply, i.e. you've got a mixture of unread, selected, and seen/read articles, the bracketed number goes into one of these formats:

  • [U:T] — there are U unread articles of T total (U<T).
  • [S/T] — there are S selected articles of T total (S<U=T).
  • [S/U:T] — there are S selected of U unread of T total (S<U<T).

If there are any selected articles at all (S>0), the info between the brackets gets high-lighted — showing that something is selected, but not all the unread articles. iykyk 💅

Notice: consolidated menus only work with the subject and lexical sorting methods. no exceptions bestie, sorry. 😭

Variables related to consolidated menus are: auto-select-closed, consolidated-menu, counter-delim-left, counter-delim-right, counter-padding, save-closed-mode.


🔥 THE JUNK-ARTICLES AND LEAVE-NEXT COMMANDS 🔥

The J {junk-articles} command is a super flexible icon that can do all sorts of attribute changes — on individual articles, on all the articles on the current menu page, on all articles with a specific attribute, or on all available articles. it's giving multitool. 🛠️

To get at all the functions of this command, you might have to hit the J key up to four times, looping through different one-line menus:

  • Mark Read — this submenu lets you mark articles read.
  • Unmark — this submenu lets you mark articles unread.
  • Select — this submenu lets you select articles based on their attribute.
  • Kill — this submenu lets you mark articles read and remove them from the menu based on their attribute.

The L {leave-next} command is basically an extension of the J command with a fifth menu:

  • Leave — this menu lets you mark articles for later handling with the leave-next attribute, which keeps the article unread until you explicitly change the attribute (like, by reading it) or until it's expired.

For each of these submenus, nn will list the most plausible choices you may use — but fr fr, all of the following answers can be used at every single submenu. And once you've entered a choice, nn will ask you whether the change should be made to all menu pages or just the current page. always checking in, so polite. 🫶

  • J — Show next submenu.
  • L — Change attribute on all leave articles.
  • N — Change attribute on all leave-next articles.
  • R — Change attribute on all read articles.
  • S — Change attribute on all seen articles.
  • U — Change attribute on all unmarked (i.e. unread) articles.
  • A — Change attribute on all articles no matter their current attribute.
  • * — Change attribute on all selected articles on the current page.
  • + — Change attribute on all selected articles on all pages.
  • a-z0-9 — Change attribute on one or more specific articles on the current page. You end the list of articles by a space or by using one of the other choices described above.
  • . — Change attribute on current article.
  • , / / — Move the current article down or up the menu without changing any attributes. just repositioning, no drama. 🌸

✨ READING MODE COMMANDS ✨

Okay so bestie, reading mode is literally the main character era of nn — the selected articles get served to you one page at a time 🎀.

To get the next page of an article, you just hit space, and when you're already sitting on the last page of an article, hit space again to slide into the next selected article. Here's the little tea though: articles are normally marked read the moment you move on to the next article, but if you go back to the menu, quit nn, whatever — the attribute on the current article is retained. Noted. 💅

And when you're on the last page of the last article? Hit space and you enter selection mode on the next group (or the current group, if reading mode got entered via the Z command). Slay.

So to actually read an article, here are the text-scrolling commands at your disposal:

  • space, {continue} — scroll one page forward, or keep going to the next article or group exactly like described above. 🦋
  • backspace / delete, {page-1} — go one page backwards in the article.
  • d, {page+1/2} — scroll one half page forward.
  • u, {page-1/2} — go one half page backwards.
  • return, {line+1} — scroll a single line forward in the article.
  • tab, {skip-lines} — skip over lines that start with the same character as the last line on the current page. This is lowkey iconic for hopping over included text, or jumping to the next file in a shell archive. ✨
  • ^, {page=1} — move to the first page (header not included, bestie) of the article.
  • $, {page=$} — move to the last page of the article.
  • gN, {line=@} — move to line N in the article.
  • /regexp, {find} — search forward for text matching the regular expression regexp in the article. If it finds a match, the text gets highlighted. ⭐
  • ., {find-next} — repeat the search for the last regular expression.
  • h, {page=0} — show the header of the article, then continue from the top of the article.
  • H, {full-digest} — if the current article was extracted from a digest, show the entire digest article, header and all. Another H command takes you back to the current subarticle.
  • D, {rot13} — turn rot13 (caesar) decryption on and off for the current article, and redraw the current page. ⚠️ Heads up: if the article is saved while it's decrypted on your screen, it gets saved in decrypted form too. You've been warned, bestie.
  • c, {compress} — turn compression on and off for the current article and redraw the current page. With compression on, multiple spaces and tabs collapse into a single space. This makes right-justified text — the kind that separates words with several spaces — so much easier to read. (See also the compress variable.)

Now, the commands for moving around between the selected articles:

  • n, {next-article} — move to the next selected article. This skips the rest of the current article, marks it read, and jumps straight to the first page of the next selected article (or to the next group, if that was the last selected article).
  • l, {leave-article} — mark the current article with the leave attribute and continue to the next selected article. Once all the selected articles in the current group have been read, these left-over articles can be automatically selected and shown one more time, or the whole treatment can be postponed until the next time you enter the group. This is especially chef's-kiss useful when you spot an article you might want to respond to — unless one of the following articles is already saying exactly what you intended to say. 🫶
  • L, {leave-next} — mark the current article with the leave-next attribute and continue with the next selected article.
  • p, {previous} — go to the previous article.
  • k, {next-subject} — kill subject. Skips the rest of the current article and all following articles with the same subject, marking the skipped ones read. To kill a subject permanently, use the K command.
  • *, {select-subject} — show the next article with the same subject (even if it isn't selected). This command selects all following articles with the same subject as the current article (similar to the * command in selection mode). Pro move: in selection mode, select only the first article on a subject, then select all the follow-ups in reading mode once you decide the article is actually interesting. 😌
  • a, {advance-article} — go to the following article on the menu even if it's not selected. This skips the rest of the current article and jumps straight to the first page of the next article (it will not skip to the next group, even if that was the last article). The attribute on the current article gets restored — except the unread attribute, which changes to seen.
  • b, {back-article} — go to the article before the current article on the menu, even if it's not selected. Basically a but the other direction. 💫

And these next ones do an immediate return from reading mode back to selection mode in the current group, or skip you to the next group:

  • =, {goto-menu} — return to selection mode in the current group (think of = as the "icon" of the selection menu). Everything you read so far gets marked read.
  • N, {next-group} — skip the rest of the selected and unread articles in the current group and go directly to the next group. Only the read (and seen) articles in the current group get marked as read.
  • X, {read-skip} — mark all articles in the current group as read and go directly to the next group. (You will be asked to confirm this one, don't worry.)

Related variables: case-fold-search, charset, compress, data-bits, date, header-lines, mark-overlap, monitor, overlap, scroll-clear-page, stop, trusted-escape-codes, wrap-header-margin.


🌸 PREVIEWING ARTICLES IN SELECTION MODE 🌸

So in selection mode you can peek at one specific article on the menu without diving into reading mode for every single selected article. The commands below enter reading mode for one article only, then bounce you right back to menu mode immediately after (this depends on the setting of the preview-continuation variable, iykyk).

If there are more than 5 free lines chilling at the bottom of the menu screen, nn will use that space to show you the article (and a minimal preview window can be permanently allocated with the window variable). If not? The screen gets cleared to show you the article. No free real estate, bestie. 😭

After previewing an article, it gets marked read (if the preview-mark-read variable is set), and the following article becomes the current article.

  • %x, {preview} — preview article x.
  • %%, {preview} — preview the current article.

While the article is being shown, these reading mode commands are so useful:

  • =, {goto-menu} — skip the rest of the current article and return to menu mode.
  • n, {next-article} — skip the rest of the current article and preview the next article.
  • l, {leave-article} — mark the article as selected (!) on the menu so you can handle it later. Then skip the rest of the current article and preview the next article. 🎀
  • %y, {preview} — preview article y .

If the auto-preview-mode variable is set, then just hitting the article id in menu mode drops you into preview mode on that specified article. Iconic behaviour, honestly.

Related variables: auto-preview-mode, min-window, preview-continuation, preview-mark-read, window. 💖

💾 SAVING ARTICLES 💾

okay bestie, this is the part where we actually keep stuff 🎀 these commands save articles into files, unpack archives, decode binaries, the whole vibe. and the glow-up here is that you can use them in both reading mode (to save the article you're looking at rn) AND selection mode (to save one or a whole lil squad of articles off the menu). versatile queen behavior 💅

here's the tea on how saving works:

  • saved articles get appended to the file(s) you pick, and each one is followed by an empty line 🌸
  • both files and directories get created as needed, no stress
  • when an article's been saved, you get a message telling you how many lines got saved — but only if the save-report variable is set (default on ✨)

the commands, bestie 🫶

  • S {save-full} — saves articles including the full article header. the whole thing, no skimping 👑
  • O {save-short} — saves articles with a short header that has only the name of the sender, the subject, and the posting date of the article. concise and cute.
  • E {save-header} — saves only the header of the articles. nothing else, just the header vibe.
  • W {save-body} — writes the article with no header at all. just the body, periodt.
  • :print {print} — prints the article 🖨️ instead of a file name, this one prompts you for the print command that the current article gets piped to. the default print command is set at compile time, but you can change it by setting the printer variable. the output is identical to what the O command gives you, fr fr.
  • :patch {patch} — sends articles through patch(1) (or whatever program you've got in the patch-command variable). instead of a file name, you get prompted for the name of a directory where you want the patch command to run. then nn pipes the body of the article through the patch command 🩹
    • the output from the patch process shows up on screen AND gets appended to a file named Patch.Result in the patch directory.
  • :unshar {unshar} — unshars articles 📦 you get prompted for the name of a directory where you want nn to unshar the articles. nn then pipes the proper parts of the article body into a Bourne Shell whose working directory is set to the directory you specified.
    • while it's unpacking, the normal output from the unshar process appears on the screen, and the menu or article text gets redrawn when the process is done ✨
    • the output also gets appended to a file named Unshar.Result in the unshar directory.
    • the file named by unshar-header-file (default "Unshar.Headers") in the unshar directory will hold the header and initial text (the stuff before the shar data) from the article. you can peek at the Unshar.Headers file using the G {goto-group} command 👀
  • :decode {decode} — decodes uuencoded articles into binary files 🧚 you get prompted for the name of a directory where you want nn to drop the decoded binary files (the file names come straight from the uuencoded data).
    • nn will combine several articles into single files as needed, and you can even decode unrelated packages (into the same directory!) with one single decode command. multitasking icon 💅
    • to decode a binary file that spans several articles, nn may have to ignore lines that fail the normal sanity checks on uuencoded data instead of treating them as transmission errors. so it is strongly recommended to check the resulting decoded file using the checksum that's normally contained in the original article. (and ngl, you're also supposed to do this after decoding with a stand-alone uudecode program.)
    • the header and initial information in the decoded articles get saved in the file named by decode-header-file (default "Decode.Headers") in the same directory as the decoded files.
    • if decode-skip-prefix is non-null, :decode will attempt to ignore up to that many characters on each line to find the encoded data. this is especially useful in some binaries groups where files are both uuencoded and packed with shar — nn will ignore the prefix that shar added to each line, and so it can unshar, concatenate, and decode multi-part postings automatically 🔥

in reading mode, these keys also invoke the save commands:

  • s — same as S.
  • o — same as O.
  • w — same as W.
  • P — same as :print.

the save commands prompt for a file name, and that name gets expanded according to the rules in the section on file name expansion below 📝 for each group you can specify a default save file in the init file — either tied to the group presentation sequence, or in a separate save-files section (see below). if a default save file exists for the group, nn will show it on the prompt line when asking for the file name. you can edit that name like normal, but if you kill the entire name immediately, nn replaces the default name with the last file name you entered. and if you kill that one too? blank line, bestie. enjoy it 🙈

if the quick-save variable is set, nn will only prompt for a save file name when the current article is inside a folder — otherwise, the default save file from the init file gets used unconditionally.

if the file (and the directories in the path) doesn't exist, nn will ask whether the file (and the directories) should be created.

if the file name contains an asterisk, like this:

part*.shar

then nn saves each of the articles in uniquely named files, constructed by replacing that asterisk with numbers from the sequence 1, 2, 3, etc. 🎀 the format of the string that replaces the * can be changed with the save-counter variable, and the first number to use can be changed via save-counter-offset.


in selection mode, nn prompts you for the identifier of one or more articles you want to save. when you're done saving, just hit space. the saved articles get marked read ✅

  • if you enter an asterisk * when prompted for an article to save, nn automatically saves all the selected articles on the current menu page and marks them read.
  • likewise, if you enter a plus +, nn saves all the selected articles on all menu pages and marks them read.

this is so useful for unpacking an entire package with the :unshar and :decode commands 👑 and it can also be used together with the save selected articles feature to save a selection of articles in separate, successively numbered files.

⚠️ but do not confuse these two concepts! the S* and S+ commands can save the selected articles into a single file as well as into separate files, and the save-in-separate-files feature can be used when saving individual articles too — either in selection mode or in article reading mode. same energy, different tools, iykyk.

when articles are saved in a file with a full or partial header, any header lines inside the body of the article get escaped with a tilde (like ~From: ...) so nn can split the folder into separate articles 🌸 that escape string can be redefined with the embedded-header-escape variable.

articles can optionally be saved in MAIL or MMDF compatible format by setting the mail-format and mmdf-format variables ✨ these variables only specify the format used when creating a new folder — appending to an existing folder gets done in that folder's format (unless folder-format-check is false).

related variables, bestie: confirm-append, confirm-create, decode-header-file, decode-skip-prefix, default-save-file, folder-save-file, edit-patch-command, edit-print-command, edit-unshar-command, folder, folder-format-check, mail-format, mmdf-format, patch-command, printer, quick-save, save-counter, save-counter-offset, save-report, suggest-default-save, unshar-command, unshar-header-file.


🗂️ FOLDER MAINTENANCE 🗂️

when more than one article is saved in a folder, nn can split the folder, and then each article inside it can be treated like a separate article 🙌

which means you can save, decode, reply, follow-up, etc. on them exactly like you would with the original article. iconic.

you can also cancel (delete) individual articles in a folder using the normal C {cancel} command described later 🗑️ and when you quit out of the folder, you get the option to remove the cancelled articles from the folder.

the original folder gets saved in a file named BackupFolder~ in the .nn directory (see the backup-folder-path variable) — by renaming or copying the old folder, whichever is appropriate. once the folder has been compressed, the backup folder gets removed unless the keep-backup-folder variable is set.

⚠️ if all articles in a folder are cancelled, the folder will be removed or truncated to zero length (whatever directory and file permissions allow). and in that case, no backup folder is retained even when keep-backup-folder is set! truly the drama of it all 😭

if the trace-folder-packing variable is set, nn will show you which articles are kept and which are removed while the folder is being rewritten 👀

folders get rewritten in the format of the original folder, i.e. the mail-format and mmdf-format variables are ignored.

related variables: backup-folder-path, keep-backup-folder, trace-folder-packing.

💾 FILE NAME EXPANSION 💾

okay bestie so whenever a save command is like "hey give me a file name," nn is secretly doing a little ✨glow-up✨ on whatever you typed. here's the whole tea:

  • +folder — the + gets swapped out for whatever's chillin' in the folder variable (default is "~/News/"), which gives you a file name inside the folder directory. examples for days:
+emacs, +nn, +sources/shar/nn
  • + — just one lonely plus? she gets replaced by the expansion of the file name sitting in the default-save-file variable (or by folder-save-file when you're saving from a folder, iykyk).
  • ~/file — the ~ is giving "environment variable HOME" and gets swapped for the contents of it, aka the path name of your home directory. examples:
~/News/emacs, ~/News/nn, ~/src/shar/nn
  • ~user/file — the ~user bit gets replaced by that user's home directory as defined in the /etc/passwd file. 🫶
  • |command-line — instead of writing to a file, your articles get piped to the given shell (/bin/sh) command-line. every save or write command makes its own separate pipe, BUT all the articles you save or write in one single command (in selection mode) all get fed as input to that same shell command. example:
| pr | lp

this prints the articles on the printer after they've been piped through pr. iconique.

  • and get this — you can make separate pipes for each saved article by using a double pipe symbol at the start of the command, like:
|| cd ~/src/nn ; patch

and these symbols get expanded inside a file name or command too:

  • $F — expands to the name of the current group with the periods replaced by slashes, e.g. rec/music/synth.
  • $G — expands to the name of the current group.
  • $L — expands to the last component of the name of the current group. use this to create default save file names like +src/$L in the comp.sources groups. 💅
  • $N — expands to the (local) article number, e.g. 1099. ⚠️ in selection mode it's only allowed at the end of the file name! no negotiating.
  • $(VAR) — replaced by the string value of the environment variable VAR.

so using all these lil symbols, a simple naming scheme for "default folder name" is +$G, which uses the group name as the folder name. another possibility is +$F/$N. slay.

like we said up there, you can also tell nn to save a whole series of files into separate, unique files. all it takes is an asterisk somewhere in the file name, e.g.

+src/hype/part*.shar

this makes each of the articles get saved into separate, unique files named part1.shar, part2.shar, and so on — always picking a part number that results in a unique file name (so if part1.shar already existed, the first article goes into part2.shar, the next into part3.shar, and so on, forever and ever 💖).

related variables: default-save-file, folder, folder-save-file, save-counter, save-counter-offset.


🌸 FILE AND GROUP NAME COMPLETION 🌸

when you're entering a file name or a news group name, there's a lil completion feature you can vibe with using the space, tab, and ? keys. it's giving autocomplete but make it ✨nn✨.

  • hitting space anywhere while you're typing will complete the current component of the file name or group name with the first available possibility. lowkey magic.
  • if that possibility isn't the one you want, just keep hitting space until it shows up. keep going bestie.
  • once the right completion appears, you can just keep typing the file or group name like nothing happened — or you can hit tab to fix the current component and grab the first possibility for the next component, then use space to cycle through the other possible completions.
  • the ? key produces a list of the possible completions of the current component. if the list is too long for the space available on screen, you can just hit the key again to get the next part of the list. no cap.
  • the current completion can be deleted with the erase key. bye bye 👋

the default value for a file name is the last file name you entered, so if you hit space as the very first character after the prompt, that last file name gets repeated (and yes, you can edit it if you want 🎀). in some cases a string will already be written for you in the prompt line, and to snag the default value in those cases you use the kill key. which also means: if you want neither the initial value nor the default value, you have to hit kill twice to get a clean prompt line. yes really, twice. two kills. 💀

related variables: comp1-key, comp2-key, help-key, suggest-default-save.

✨ POSTING AND RESPONDING TO ARTICLES ✨

ok bestie so this is the part where you go from reader to poster, and honestly? it's giving main character energy 🎀 Whether you're in selection mode or reading mode, you can post brand-new articles, follow up on articles, send replies straight to an author's inbox, and send mail to another user with the option of tucking an article inside the letter. In reading mode your response is aimed at the current article. In selection mode? nn's gonna prompt you for an article to respond to. Different vibes, same energy.

Here's the command menu, and yesss the lower-case equivalents are also available in reading mode:

  • R — {reply} — reply through mail to the author of the article. This is the preferred way to respond to an article unless you think your reply is of general interest. like, don't be that person who follows up on everything 💀
  • F — {follow} — follow-up with an article in the same newsgroup (unless an alternative group is specified in the article header). The distribution of the follow-up is normally the same as the original article, but this can be modified via the follow-distribution variable.
  • M — {mail} — mail a letter or forward an article to a single recipient. In selection mode, you will be prompted for an article to include in your letter, and in reading mode you will be asked if the current article should be included in the letter. You will then be prompted for the recipient of the letter (default recipient is yourself) and the subject of the letter (if an article is included, you may hit space to get the default subject which is the subject of the included article). The header of the article is only included in the posted letter if it is forwarded (i.e. not edited), or if the variable include-full-header is set.
  • :post — {post} — post a new article to any newsgroup. This command will prompt you for a comma-separated list of newsgroups to post to (you cannot enter a space because space is used for group name completion as described below). no spaces, bestie, I'm serious If you enter ? {help-key} as the first key, nn will show you a list of all available news groups and their purpose. While paging through this list, you can enter q to quit looking at the list. You can also enter / followed by a regular expression (typically a single word) which will cause nn to show a (much shorter) list containing only the lines matching the regular expression. Normally, you will be prompted for the distribution of the article with the default take from default-distribution, but this can be changed via the post-distribution variable.

the actual writing part (yes this is where you type) 🦋

Generally, nn will construct a file with a suitable header, optionally include a copy of the article in the file with each non-empty line prefixed by a > character (except in mail mode), and invoke an editor of your choice (using the EDITOR environment variable) on this file, positioning you on the first line of the body of the article (if it knows the editor). icon behavior honestly 💅

When you have completed editing the message, it will compare it to the unedited file, and if they are identical (i.e. you did not make any changes to the file), or it is empty, the operation is cancelled. no notes, no post, we move on.

Otherwise you will be prompted for an action to take on the constructed article (enter first letter followed by return, or just return to take the default action):

a)bort c)c e)dit h)old i)spell m)ail p)ost r)eedit s)end v)iew w)rite 7)bit
Action: (post article)

You now have the opportunity to perform one of the following actions:

  • a — throw the response away (will ask for confirmation).
  • c — mail a copy of a follow-up to the poster of the article.
  • e — edit the file again.
  • h — hold response for later completion.
  • i — run an (interactive) spell-checker on the text.
  • m — mail a (blind) copy to a specified recipient.
  • n — same as abort (no don't post).
  • p — post article (same as send).
  • r — throw away the edited text and edit the original text.
  • s — send the article or letter.
  • v — view the article (through the pager).
  • w — append it to a file (before you send it).
  • y — confirm default answer (e.g. yes post it), or
  • 7 — strip the high-order bit from all characters in the message.

the 7-bit situation 😭

If you have selected a 7-bit character set (this is determined by the values of the charset and data-bits variables), nn will not allow you to post an article or send a letter whose body contains characters with the high-order bit set. It will warn you after you have first edited the message and disable the c)c, m)ail, p)ost, s)end and y)es actions. You can then either e)dit the message to delete those characters, use 7)bit to strip the high-order bits, a)bort the message, or h)old it and select an 8-bit character set from nn.

To complete an unfinished response saved by the h)old command, simply enter any response action, e.g. R {reply}. This will notice the unfinished response and ask you whether you want to complete it now. Only one unfinished response can exist at a time. Notice that the $A environment variable may no longer be valid as a path to the original article when the response is completed. yeah. that one. be aware 🫶


8-bit characters & the MIME thing 🌈

If your message contains 8-bit characters, the charset variable is not set to "unknown" and the message does not already have a MIME-Version or Content-XXX header, nn will add the following headers to your message before sending it:

MIME-Version: 1.0
Content-Type: text/plain; charset=charset
Content-Transfer-Encoding: 8bit
It must be noted that sending 8-bit characters over the current news and mail networks is risky at best; although large parts of the network will pass through such characters unchanged, high-order bits may occasionally be stripped. Although the MIME standard provides solutions for this by encoding the characters, this is not yet supported by nn. Adding the above headers is an interim solution that is compatible with current practice and is much better than just sending the message without any hints about the character set used. so like… it's a bandaid, but a cute and honest bandaid 🩹

append-signature-mail, append-signature-post, charset, data-bits, default-distribution, follow-distribution, post-distribution, edit-response-check, editor, include-art-id, include-full-header, included-mark, mail-header, mail-record, mail-script, mailer, mailer-pipe-input, news-header, news-record, news-script, orig-to-include-mask, pager, query-signature, record, response-check-pause, response-default-answer, save-counter, save-counter-offset, save-report, spell-checker.

💖 JUMPING TO OTHER GROUPS 💖

okay so by default nn will present the news groups in a predefined sequence (peep the section on Presentation Sequence later on, bestie). But if you wanna override that sequence and go look at literally any other group, the G {goto-group} command — available in both selection and reading mode — lets you move freely between all the newsgroups. 💅

Furthermore, the G command enables you to open folders and other files, to read old articles you have read before, and to grep for a specific subject in a group. iconic ✨

It is important to notice that normally the goto command is recursive, i.e. a new menu level is created when the specified group or folder is presented, and when it has been read, nn will continue the activity in the group that was presented before the goto command was executed. However, if there are unread articles in the target group you can avoid entering a new menu level by using the j reply described below. The current menu level (i.e. number of nested goto commands) will be shown in the prompt line as "<N>" (in reverse video). 👑

The goto command is very powerful, but unfortunately also a little bit tricky at first sight, because the facilities it provides depend on the context in which the command is used. iykyk 😭

When executed, the goto command will prompt you for the name of the newsgroup, folder, or file to open. It will use the first letter you enter to distinguish these three possibilities:

  • return — An empty answer is equivalent to the current newsgroup. 💖
  • letter — The answer is taken to be the name of a newsgroup. If a newsgroup with the given name does not exist, nn will treat the answer as a regular expression and locate the first group in the presentation sequence (or among all groups) whose name matches the expression. 🔍
  • + — The answer is taken to be the name of a folder. If only + is entered, it is equivalent to the default save file for the current group. 🎀
  • / or ./ or ~/ — The answer is taken to be the name of a file, either relative to the current directory, relative to your home directory, or an absolute path name for the file. 📁
  • % — In reading mode, this reply corresponds to reading the current article (and splitting it as a digest). In selection mode, it will prompt for an article on the menu to read. 👀
  • @ — This choice is equivalent to the archive file for the current group. 🗄️
  • = and number — These answers are equivalent to the same answers described below applied to the current group (e.g. G return = and G = are equivalent). ✨

Specifying a folder, a file, or an article (with %) will cause nn to treat the file like a digest and split it into separate articles (not physically!) which are then presented on a menu in the usual way, allowing you to read or save individual subarticles from the folder. no cap 🫶

When you enter a group name, nn will ask you how many articles in the group you want to see on the menu. You can give the following answers:

  • a number N — In this case you will get the newest N articles in the group, or if you specified the current group (by hitting return to the group name prompt or entering the number directly), you will get that many extra articles included on the same menu (without creating a new menu level). 🔢
  • j — This answer can only be given if there are unread articles in the group. It will instruct nn to jump directly to the specified group in the presentation sequence without creating a new menu level. 🦘
  • u — This instructs nn to present the unread articles in the group (if there are any). If you have already read the group (in the current invocation of nn), the u answer will instruct nn to present the articles that were unread when you entered nn. 🌸
  • a — This instruct nn to present all articles in the group. 💯
  • sword or =word — This instructs nn to search all articles in the groups, but only present the articles containing the word word in the subject. Notice that case is ignored when searching for the word in the subject lines. 🔎
  • nword — Same as the s form except that it searched for articles where the sender name matches word. ✉️
  • eword — Same as the s form except that it Psearched for articles where either the subject or the sender name matches word. 😭
  • word = /regexp — When the first character of the word specified with the s, n, and e forms is a slash /, the rest of the input is interpreted as a regular expression to search for. Notice that regular expression matching is case insensitive when case-fold-search is set (default). 🧚
  • return — The meaning of an empty answer depends on the context: if there are unread articles in the specified group the unread articles will be presented, otherwise all articles in the group will be included in the menu. 💜

If you specified the current group, and the menu already contains all the available articles, nn will directly prompt for a word to search for in the subject of all articles (the prompt will be an equal sign.) ⭐

When the goto command creates a new menu level, nn will not perform auto kill or selection in the group. You can use the + command in menu mode to perform the auto-selections. 🎯

There are three commands in the goto family:

  • G {goto-group} — This is the general goto command described above. 👑
  • B {back-group} — Backup one or more groups. You can hit this key one or more times to go back in the groups already presented (including those without new articles); when you have found the group you are looking for, hit space to enter it. ⏪
  • A {advance-group} — Advance one or more groups. This command is similar to the B command, but operates in the opposite direction. ⏩
  • N {next-group} — When used within an A or B command, it skips forward to the next group in the sequence with unread articles or which has previously been visited. ⏭️
  • P {previous} — When used within an A or B command, it skips backwards to the preceding group in the sequence with unread articles or which has previously been visited. ⏮️

Once you have entered an A or B command, you can freely mix the A, B, P, and N commands to find the group you want, and you can also use the G command to be prompted for a group name. 🔄

To show the use of the goto command some typical examples on its use are given below:

Present the unread articles in the dk.general group

G dk.general return u

Jump directly to the gnu.emacs group and continue from there

G gnu.emacs return j

Include the last 10 READ articles in the current group menu

G 10 return

Find all articles in rec.music.misc on the subject Floyd

G rec.music.misc return
= floyd return

Open the folder +nn

G +nn return

Split current article as a digest (in reading mode)

G %

Related variables: case-fold-search, default-save-file, folder-save-file ✨

💀 AUTOMATIC KILL AND SELECTION 💀

okay bestie so here's the tea: when there's a subject or an author you're obsessed with, or one you find completely uninteresting, you can just tell nn to auto-select or auto-kill articles with specific subjects or from specific authors. easy. These instructions live in a kill file, and the most common kinds of entries can be made with this command right here:

  • K {kill-select} — drops an entry into your personal kill file. You specify what goes in it during a lil short dialog that we're gonna walk through in detail below. Works in both selection mode and reading mode. ✨

Entries in the kill file can apply to a single newsgroup or to all newsgroups. And they can be permanent, or they can expire a given number of days after they were entered. slay, flexible.

To bump performance, nn uses a compiled version of the kill file that gets read in when nn is invoked. That compiled kill file will automatically update itself if the normal kill file has been modified. no cap, it just knows. 🙈

Here's the dialog that builds the kill file entry:

  • AUTO (k)ill or (s)elect (CR => Kill subject 30 days) — if you literally just want nn to kill all articles with the subject of the current article (reading mode) or a specific article (nn will prompt you for which one in selection mode), just smash return. That makes an entry in the kill file killing the current (or specified) subject in the current group for a period of 30 days (which should be enough for the discussion to die out, honestly). You can control the default kill period, or flip it into a "select" period, via the default-kill-select variable. And if that "default behaviour" is not the vibe you want, just answer k or s to kill or select articles respectively, and you'll get taken through the rest of the questions. 💅
  • AUTO SELECT on (s)ubject or (n)ame (s) — (the SELECT gets swapped out for KILL depending on your previous answer). Here you say whether you want the kill or select to depend on the subject of the article (s or space) or on the name of the author (n).
  • SELECT NAME: — (again, SELECT may get substituted with KILL and SUBJECT may replace NAME). Now you gotta enter a name (or subject) to select (or kill). In reading mode, you can just hit return (or %) to use the name (or subject) of the current article. In selection mode, you can use the name (or subject) from an article on the menu by answering with % followed by the matching article identifier. When the name or subject is taken from an article (the current one, or one from the menu), nn will only select or kill articles where the name or subject matches the original name or subject exactly, including case. If the first character you type at the prompt is a slash /, the rest of the line is used as a regular expression to match the name or subject (case insensitive). Otherwise, nn will select or kill articles which contain the specified string anywhere in the name or subject (ignoring case).
  • SELECT in (g)roup 'dk.general' or in (a)ll groups (g) — now you specify whether the selection or kill should apply to the current group only (g or space) or to all groups (a).
  • Lifetime of entry in days (p)ermanent (30) — now you set the lifetime of the entry: either type a number for how many days it should be active, or p to make it a permanent entry. An empty reply is equivalent to 30 days.
  • CONFIRM SELECT .... — finally you get asked to confirm the entry, and you should especially clock the presence or absence of the word exact, which tells you whether an exact match applies for the entry. 👀

Related variables: default-kill-select, kill.


📜 THE FORMAT OF THE KILL FILE 📜

The kill file is one line per entry. Empty lines and lines starting with a # character are ignored. nn automatically sticks a # character in the first position of expired entries when it compiles the kill file, and then you can edit the kill file manually from time to time to clean those out. lil housekeeping moment 🧹

Each line has this format:

[expire time :] [group name] : flags : string [: string]...

Permanent entries have no expire time (in which case the colon is omitted as well!). Otherwise, the expire time defines the time (as a time_t value) when the entry should be expired.

The group name field can have three forms:

  • news.group.name — if it's the name of a single news group (e.g. comp.unix), the entry applies to that group only.
  • /regular expression — if it starts with a slash / followed by a regular expression (e.g. /^news\..*), the entry applies to all groups whose name is matched by the regular expression.
  • empty — an empty group field applies the entry to all groups.

The flags field is a list of characters identifying the type of entry, and how each string field is interpreted. When used, the flag characters must be used in the order described below:

  • ~ (optional) — when this flag is present on any of the entries for a specific group, it causes all entries which are not auto-selected to be killed. It's a simple way of saying: I'm interested in this and that, but nothing else. iconic honestly 💅
  • + or ! (optional) — specify an auto-select + or an auto-kill ! entry, respectively. If neither is used, the article is neither selected nor killed, which is useful in combination with the ~ flag.
  • > (optional) — when used with a subject (flag s), the kill entry only matches follow-ups to that subject (i.e. where the Subject: line starts with Re:). For example, to kill all "Re:"'s in rec.humor use this kill entry: rec.humor:!>s/:.
  • < (optional) — when used with a subject (flag s), the kill entry only matches base articles with that subject (i.e. where the Subject: line does not start with Re:). For example, to kill all articles asking for help (but not follow-ups) in the tex group, add this to your kill file:
comp.text.tex:!s</:^HELP
  • n or s or a (mandatory) — say whether the corresponding string applies to the name n or to the subject s of an article. If flag a is used, the corresponding string is ignored (but must still be present!), and the entry applies to articles with a non-empty References: line.
  • / (optional) — specifies that the corresponding string is a regular expression which the sender or subject is matched against. If not specified, a simple string match is performed using the given string.
  • = (optional) — specifies that the match against the name or subject is case sensitive. Furthermore, when regular expression matching isn't used, the name or subject must be the same length as the string to match. Otherwise, the match will be case insensitive, and a string may occur anywhere in the name or subject to match.
  • | or & (mandatory if multiple strings) — if more than one string is specified, the set of flags corresponding to each string must be separated by either an or operator | or an and operator &. The and operator has a higher precedence than the or operator, e.g. a complex match expression a|b&c|d will succeed if either of a, b&c, or d matches.

The string field in the entry is the name, subject or regular expression that gets matched against the name or subject of each article in the group (or all groups). Colons and backslashes must be escaped with a backslash in the string. ⚠️

Example 1: Auto-select articles from 'Tom Collins' (exact) on subject 'News' in all groups:

:+n=&s:Tom Collins:News

Example 2: Kill all articles which are neither from 'Tom' or 'Eve' in some.group. Select only articles from Eve:

some.group:~n:Tom
some.group:+n:Eve

The second example can also be written as a single entry with an or operator (in this case, the select/kill attribute only applies to the succeeding strings):

some.group:~n|+n:Tom:Eve

To remove expired entries, to "undo" a K command, and to make the more advanced entries with more than one string, you will have to edit the kill file manually. To recompile the file, you can use the :compile command. When you invoke nn, it will also recompile the kill file if the compiled version is out of date. ✅


🐚 SHELL ESCAPES 🐚

The ! commands available in selection mode and reading mode are identical in operation (with one exception). When you enter the shell escape command, you get prompted for a shell command. That command gets fed to the shell specified in the shell variable (default loaded from the SHELL environment variable, or /bin/sh) after these substitutions have been performed on the command:

  • File name expansion — the earlier described file name expansions will be performed on all arguments.
  • $G — will be substituted with the name of the current news group.
  • $L — will be substituted with the last component of the name of the current news group.
  • $F — will be substituted with the name of the current news group with the periods replaced by slashes.
  • $N — will be substituted with the (local) article number (only defined in reading mode).
  • $A — is replaced by the full path name of the file containing the current article (only defined in reading mode).
  • % — same as $A.
  • $(VAR) — is replaced by the string value of the environment variable VAR.

When the shell command is completed, you'll be asked to hit any key to continue. If you hit the ! key again, you'll get prompted for a new shell command. Any other key will redraw the screen and return you to the mode you came from. 🦋

Related variables: shell, shell-restrictions.

💫 MISCELLANEOUS COMMANDS 💫

Okay bestie, here's a lil grab-bag of extra commands — and the cute part is they work in both selection mode and reading mode. Versatile queens. 👑

  • U, {unsub} — Unsubscribe from the group you're currently in. Like, you literally won't see it again unless you explicitly ask for it. 🙈 If the variable unsubscribe-mark-read is set, then every article in that group gets marked read the moment you unsubscribe. And if the variable keep-unsubscribed is not set? The group gets yeeted from .newsrc. If you're not subscribed to the group, nn will give you the option to resubscribe — which pairs adorable with the G command for resubscribing a group. ✨
  • C, {cancel} — Cancel (aka delete) an article in the current group or folder. Cancelling stuff inside a folder means the folder gets rewritten when it's closed, fyi. In selection mode you'll get prompted for the identifier of the article you wanna cancel. And like… normal users can only cancel their own articles. No cancelling other people's posts, bestie, that's not your business. 😭 Also go peek at the folder maintenance section.
  • Y, {overview} — Gives you an overview of all the groups that have unread articles. A little vibe check of your unread life. 🌈
  • ", {layout} — Changes the menu layout in selection mode. The menu gets redrawn using the next layout, cycling through ..., 2, 3, 4, 0, 1, ... 🔄

Most of the commands in nn are bound to a key, so literally one keystroke and boom, done. 💅 But there are a few commands that just cannot be bound to a key directly. Tragic, I know.

So, as the keystroke command descriptions show, every command has a name, and you can activate a command by name using the extended command key — that's : for you and me. Hit that key and it'll prompt you for the name of a command (plus any parameters). For example, instead of smashing the R key to reply to an article, you could type the extended command :reply and then hit return. Same energy. The :post and :unshar commands we talked about earlier can also be bound to a key. And the complete list of commands that can be bound to keys lives in the Key Mappings section below. 📜

Now here's the extended commands that cannot be bound to a key — mostly because they need extra parameters on the prompt line, or because they shouldn't be too easy to trigger. (Main character energy requires a lil friction, yk? 🎀)

  • :admin — Enter administrative mode. This operates identically to the nnadmin(1M) program. 👑
  • :bug — Prepare and send a bug report to the nn-bugs mailing address. 🐛
  • :cd [ directory ] — Change the current working directory. If you don't hand it a directory argument, nn will prompt you for one.
  • :clear — Clear the screen (without redraw). This can be useful at the beginning of the init file (possibly guarded by "on program nn"), or inside some macros. ✨
  • :compile — Recompile the kill file. Honestly not necessary under normal operation, because nn automatically compiles the file on start-up if it's changed — but it's there for you if you modify the kill file while nn is suspended. 🛠️
  • :coredump — Abort with a core dump. For debugging purposes only. Do not do this casually bestie, I'm begging. 💀
  • :define macro — Define macro number macro as described in the Macro Definition section below. If you omit macro, the next free macro number gets chosen automatically. 🧚
  • :dump table — Same thing as the :show command described below.
  • :help [ subject ] — Online help on the subject you asked for. Omit the subject and you'll get a list of all the available topics. 🫶
  • :load [ file ] — Load the specified file. Omit the file argument and the init file gets reloaded. The sequence part (if there is one) is ignored.
  • :local variable [ value ] — Make the variable local to the current group. Any changes you make to it after that only stick until you leave the current group. If you specify a value, it gets assigned to the local variable. And heads up: to assign a new value to a boolean variable you have to use the values on and off. 🎀
  • :lock variable — Lock the specified variable so it can't be modified. 🔒
  • :man — Call up the online manual. The manual shows up as a normal folder, with the program name in the From field and the section title in the subject field. Every normal folder command works on the online manual too — so yes, you can save and print sections of the manual. Iconic, honestly. 📖
  • :map arguments — This is the command used to bind commands to keys. Fully described in the Key Mapping section below.
  • :mkdir [ directory ] — Create the directory (and all the directories in its path). If you omit the argument it'll prompt you for a directory name. 📁
  • :motd — Show the message of the day. (Maintained by the news administrator in the file "motd" in the lib directory.) This file is automatically displayed on start-up whenever it changes, if the motd variable is set. 🌞
  • :pwd — Print the path name of the current working directory on the message line. 📍
  • :q — Has no effect besides redrawing the screen if that's needed. Here's the lore: if an extended command (one prefixed by :) produces output that needs the screen redrawn, the screen won't be redrawn immediately when the variable delay-redraw is set (super useful on slow terminals). Instead, another : prompt shows up so you can enter a new extended command right away. Hitting return is enough to redraw the screen — but per the author's own experience, typing q return in that situation happens a lot, so it was made a no-op. 💀 We've all been there.
  • :q! — Quit nn without updating the .newsrc file. ⚠️ No takebacks.
  • :Q — Quit nn. This is equivalent to the normal Q command.
  • :rmail — Open your mailbox (see the mail variable) as a folder so you can read incoming messages. Heads up, this is not a full mail interface — depending on your nn configuration you might not be able to delete messages, add cc: on replies, etc. — but it gives you a quick glance at new mail without leaving nn. 📬
  • :set variable [ value ] — Set a boolean variable to true, or assign the value to a string or integer variable. The :set command is described in detail in the VARIABLES section. ✨
  • :sh — Suspend nn, or if that's not possible, spawn an interactive shell. 🐚
  • :show groups mode — Show the total number, or the number of unread articles, in the current group, depending on mode:
    • all — list the number of unread articles in all groups, including groups you've unsubscribed to.
    • total — list the total number of articles in all existing groups.
    • sequence — list unread groups in presentation sequence order.
    • subscr — list all subscribed groups.
    • unsub — list unsubscribed groups only.

Any other mode results in a listing of the number of unread articles in all subscribed groups, including those you've suppressed with the ! symbol in the group presentation sequence. And if you want just the currently unread groups in presentation sequence? Use the Y {overview} command instead. 💖

  • :show kill — Show the kill entries that apply to the current group and to all groups. 🔪
  • :show rc [ group ] — Show the .newsrc and select file entries for the current group (or the group you specified).
  • :show map [ mode ] — Show the key bindings in the current or specified mode. 🗺️
  • :sort [ mode ] — Reorder the articles on the menu according to mode, or if you omit it, according to the default sort-mode. Here are the sorting modes available:
    • arrival — list articles by local article number, which will be the same as the order in which they arrived on the system (unless groups are merged).
    • subject — articles with identical subjects are grouped together and ordered after the age of the oldest article in the group.
    • lexical — subjects in lexicographical order.
    • age — articles ordered after posting date only.
    • sender — articles ordered after the sender's name.
  • :toggle variable — Toggle a boolean variable. 🔁
  • :unread [ group ] [ articles ] — Mark the current group (or the specified group) as unread. If you omit the articles argument, the number of unread articles in the group will be set to the number of unread articles when nn was invoked. Otherwise, the argument specifies the number of unread articles. 🫣
  • :unset variable — Set a boolean variable to false, or clear an integer variable.
  • :x — Quit nn and mark all articles in the current group as read! All of them. No survivors. ⚠️💀
Related variables: backup, bug-report-address, delay-redraw, keep-unsubscribed, unsubscribe-mark-read, mail, pager, sort-mode.

🌊 CATCH UP 🌊

If you haven't read news in a while, there's probably way more news than you can cope with. Not your fault bestie, the internet is relentless. 😭 Using the option -a0, nn will drop you straight into catch-up mode.

The first question you get is whether to catch up interactively or automatically. If you tell nn to catch up automatically, it just marks every article in every group as read — bringing you completely up-to-date in one go. Clean slate, zero guilt. ✨

If you pick the interactive mode instead, nn locates all groups with unread articles, and for each group it prompts you for an action to take on that group. You select an action with a single letter followed by return. Here's the menu of moves:

  • y — Mark all articles as read in the current group.
  • n — Do not update the group. (This is the default action if you just hit return. No thoughts, just vibes. 🦋)
  • r — Enter reading mode to read the group.
  • U — Unsubscribe from the group.
  • ? — Give a list of actions.
  • q — Quit. When you quit, nn will ask whether the rest of the groups should be updated unconditionally or whether they should remain unread. 👀

👑 VARIABLES AND OPTIONS 👑

So you can totally control how nn behaves by setting (and unsetting) the variables described below. And there are several ways to set them:

  • Through command line options when nn is invoked.
  • Through assignments on the command line when nn is invoked.
  • Through global set commands in the init file.
  • Through set or local commands executed from entry macros.
  • Through the :set extended command while you're running nn.

And there are four types of variables:

  • Boolean variables
  • Integer variables
  • String variables
  • Key variables

Boolean variables control one specific function in nn — like, for example, whether the current time is shown in the prompt line. ⏰ A boolean variable is set to true with the command

set variable

and it's set to false with either of the following (they're equivalent, pick your fave 💅):

unset variable
set novariable

You can also flip a boolean variable's value with the super handy:

toggle variable

So like, for example:

set time
unset time
set notime
toggle time

Integer variables hold a number — think the size of your preview window, or the max number of articles to read per group 🌸. You set them like:

set variable value

In some cases not setting an integer value carries a special meaning, like "no minimal preview window" or "read every article in the group, idc how many there are." Wanna get that special meaning back? Say:

unset variable

For example:

set window 7
unset limit

String variables are your directory names, your default prompt values, that kind of thing. Set them with:

set variable string

Heads up bestie, the rules here are a lil specific ✨: normally the string you assign starts at the first non-blank character after the variable name and ends with the last non-blank character on the line (comments excluded). Wanna sneak leading/trailing blanks — or the comment start symbol # — into the string? You gotta escape them with a backslash \. So to set included-mark to the string " # ", you'd write:

set included-mark  \ \#\   # blank-#-blank

Wanna put a literal backslash in the string? Duplicate it: \\. And a backslash can also bring in these special characters: \a=alarm, \b=backspace, \e=escape, \f=form-feed, \n=new-line, \r=return, \t=tab.

Key variables decide which keys trigger the special functions while you're typing — line editing, completion, all that ✨. Set them with:

set variable key-name

You can lock a variable, which makes any further modification of it straight-up impossible:

lock variable

This is the move for your setup init file, which loads unconditionally, so you can enforce local conventions or restrictions 👑. Like, to pin included-mark to the string > you'd drop these into the setup file:

set included-mark >
lock included-mark

Some variables only make sense when you set them on the command line, because nn peeks at them early in startup, before the init files are even read 💅. Command-line syntax is:

variable=value

If the value has white space or special characters, it may need quoting. You can mix these in with your other options, and they get examined prior to other argument parsing.


Wanna see your current settings? The :set command's got you:

  • :set (no arguments) — gives you a listing of the variables that have been set, whether in the init file or interactively.
  • :set all — gives you a listing of all variables. Modified variables get marked with a *, local variables get marked with a >, and a locked variable gets marked with a !.
  • :set /regexp — lists every variable whose name matches the given regular expression.
  • :set partial-name + space — the space (comp1-key) key completes the variable name like usual, but as a cute lil side effect it also shows you that variable's current value in the message line.

Variables are global by default, but you can make a local instantiation of one with the :local command 💖. That local variable overlays the global one for as long as the current group is active — i.e. the global variable comes back the moment you exit the current group. Its starting value is whatever the global variable had, unless you hand it a new one in the :local command itself:

:local variable [ value ]

And now, the moment you've been waiting for: the full variable roster 👑💖

  • also-full-digest (boolean, default false) — when a digest gets split, the digest itself normally doesn't make it onto the menu, which means that initial administrative info is just... not there 😭. Setting also-full-digest makes the (unsplit) digest show up on the menu too. These articles get marked with a @ at the beginning of the subject.
  • also-subgroups (boolean, default true) — when this is set, a group name in the presentation sequence also pulls in all that group's subgroups. So like, comp.unix will also bring in comp.unix.questions, etc. When also-subgroups is not set, subgroups only show up if the group name is followed by a . — and in that case the main group itself is not included, i.e. comp.unix is not included when comp.unix. is specified in the presentation sequence, and vice-versa. Following a group name with an asterisk *, like comp.unix*, includes the group and all subgroups, no matter how also-subgroups is set. Slay.
  • append-signature-mail (boolean, default false) — when false, nn assumes your .signature file is automatically appended to responses sent via E-mail. If true, .signature gets explicitly appended to the letter (see query-signature).
  • append-signature-post (boolean, default false) — when false, nn assumes .signature is automatically appended to posted articles. If true, .signature gets explicitly appended to posted articles (see query-signature).
  • attributes symbols (string, default ....) — each element in this string is a symbol used to represent an article attribute when it's displayed on the screen. Check the section on Marking Articles and Attributes 💅.
  • auto-junk-seen (boolean, default true) — when set, articles with the seen attribute (,) get marked read when you leave the current group. If it's not set, those articles will still be either unread or marked seen the next time you enter the group (see also confirm-junk-seen and retain-seen-status).
  • auto-preview-mode (boolean, default false) — turns on Auto Preview Mode ✨. In this mode, picking an article on the menu by its article id (letter a-z) drops you straight into preview mode on that article. On top of that, the n {next-article} command previews the next article on the menu only if it has the same subject as the current article — otherwise it goes back to the menu with the cursor parked on the next article. The continue command at the end of the article and the = {goto-menu} bounce you back to the menu immediately, same as always.
  • auto-read-mode-limit N (integer, default 0) — when you're in auto reading mode, nn auto-selects all the unread articles in the group, skips the article selection phase entirely, and drops you into reading mode right after you enter the group 🔥. Auto reading mode is disabled when auto-read-mode-limit is zero; it's activated unconditionally if the value is negative, and conditionally if the value is greater than zero and the number of unread articles in the current group doesn't exceed the given value.
  • auto-select-closed mode (integer, default 1) — normally, selecting a closed subject (usually in consolidated menu mode) selects — or deselects — all unread articles with that subject (or all articles, if they're all read). You can change that behaviour via this variable's value:
    • 0: select only the first article with the subject (the one shown on the menu).
    • 1: select only the unread articles with the subject.
    • 2: select all available articles with the subject.
  • auto-select-rw (boolean, default false) — if set, the subject of an article you read or posted automatically gets used for subsequent auto-selecting (if it's not already selected). This is the most efficient way to see your own posts automatically 👑.
  • auto-select-subject (boolean, default false) — when set, selecting an article from the menu by its article id (a-z) automatically selects every other article on the menu with the same subject too.
  • backup (boolean, default true) — when set, a copy of the initial .newsrc and select files gets saved the first time they're changed. nn remembers the initial contents of those files internally, so the backup variable can be set at any time if it wasn't set on start-up.
  • backup-folder-path file (string, default "BackupFolder~") — when deleting articles out of a folder, this variable names the file where a (temporary) copy of the original folder gets saved. If the file name doesn't contain a /, the file lands in the .nn directory. Otherwise the file name is used directly as the relative or full path name of the backup file. If possible, the old folder gets renamed to the backup folder name; otherwise the old folder is copied to the backup folder.
  • backup-suffix suffix (string, default ".bak") — the suffix appended to file names to build the corresponding backup file name (see backup).
  • bug-report-address address (string, default mtpins@nndev.org) — the mail address that bug reports made with the :bug command get sent to 🐛.
  • case-fold-search (boolean, default true) — when set, string and regular expression matching ignores case 🙈. This applies to all commands matching on names or subjects, except in connection with auto-kill and auto-select, where each individual kill file entry specifies this property for itself.
  • charset charset (string, default "us-ascii") — the character set your terminal is using. Legal values are "us-ascii", "iso-8859-X" (where X is a nonzero digit), and "unknown". Setting this variable also sets the data-bits variable to the default bit width of the character set (7 for "us-ascii" and "unknown", 8 for the "iso-8859-X" sets). The value of this variable also decides whether nn allows 8-bit characters in the body of articles you're posting and letters you're mailing — unless the value is "unknown", in which case data-bits makes that call instead. If necessary, nn will tack on extra headers to the message indicating its character set.
  • check-group-access (boolean, default false) — ooh okay so when this is set, nn will do a ✨vibe check✨ on a group's readability before it shows you the menu for that group. Normally this is not necessary, because traditionally all users have access to all news groups (the good old days fr). But setting (and locking) this variable can be used to limit access to a news group via the permissions and ownership of the group's spool directory. 💅 Heads up though: this will only work for non-NNTP sites. Non-NNTP only, bestie, no exceptions.
  • collapse-subject offset (integer, default 25) — when this is set (non-negative), subject lines that are too long to show in full on the menus get "collapsed" instead of chopped — nn removes a sufficient number of characters from the subject starting at the given offset within the subject. This is super useful in source groups where the Part (01/10) string sometimes just… disappears from the menu 😭 (rude). When it's not set (or set negative), the subjects are truncated instead. Different vibes, different results.
  • columns col (integer, default screen width) — this variable is holding the screen width, i.e. how many character positions fit per line. 📏
  • comp1-key key (key, default space) — the key that gives you the first/next completion, and also the default value when nn is prompting you for a string, like a file name. ✨
  • comp2-key key (key, default tab) — the key that ends the current completion and hands you the first completion for the next component when nn is prompting for a string, e.g. a file name. So it's the "next bestie, we're done here" key. 🎀
  • compress (boolean, default false) — this one controls whether text compression (see the compress command) is turned on or off when an article is shown. And ngl, the compression is still toggled for the current article with the compress command key, no matter what this says.
  • confirm-append (boolean, default false) — when set, nn will ask for confirmation before appending an article to an existing file. (see also confirm-create) 🫶
  • confirm-auto-quit (boolean, default false) — when set, nn will ask you to confirm before quitting after you've read the last group. And if you don't confirm? nn will recycle the presentation sequence, out here looking for groups you skipped with the N {next-group} command. 👀 But bestie, it will not look for new articles that arrived since the invocation of nn. So close, yet so far.
  • confirm-create (boolean, default true) — when set, nn asks for confirmation before creating a new file or directory when saving or unpacking an article. (see also confirm-append) 🎀
  • confirm-entry (boolean, default false) — when set, nn asks for confirmation before you enter a group that has more than confirm-entry-limit unread articles (this is on the first menu level). Very useful on slow terminals if you do not want to wait until nn has drawn the first menu just so you can skip the group. 🐌
    • Answering no to the Enter? prompt makes nn skip to the next group without marking the current group as read.
    • If you answer by hitting interrupt, nn will ask the question Mark as read? — which lets you mark the current group as read before moving on to the next group.
    • And if you hit interrupt on that second question too? 😭 nn will quit immediately. Periodt.
  • confirm-entry-limit articles (integer, default 0) — specifies the minimum number of unread articles in a group for which the confirm-entry functionality gets activated. So it's the threshold that wakes confirm-entry up. ⭐
  • confirm-junk-seen (boolean, default false) — when set, nn will require confirmation before marking seen articles as read — but only when auto-junk-seen is set. 🙈
  • confirm-messages (boolean, default false) — in some cases, nn will sleep one second (or more) after it has shown a message to the user, e.g. in connection with macro debugging. Setting confirm-messages makes nn wait for you to confirm all messages by hitting any key. (It will show the symbol <> to let you know it's sitting there awaiting confirmation, like 🥺 "hello? are you there?")
  • consolidated-manual (boolean, default false) — when set, the online manual will be presented with one menu line for each program in the nn package. Organized. 👑
  • consolidated-menu (boolean, default false) — when set, nn will automatically close all multi-article subjects on entry to a group, so that each subject only occurs once on the menu page. Clean girl aesthetic menu, honestly. ✨
  • counter-delim-left (string, default "[") — the delimiter string that gets output to the left of the article counter in a closed subject's menu line.
  • counter-delim-right (string, default "] ") — the delimiter string that gets output to the right of the article counter in a closed subject's menu line. Yes it has a trailing space, do not touch it. 💅
  • counter-padding pad (integer, default 5) — okay so on a consolidated menu, the subjects might not be very well aligned, because those added [...] counters have varying lengths (so messy 😩). To (partially) remedy this, all counters — and the subjects that have no counters — are prefixed by up to pad spaces to get better alignment. Increasing it further may yield practically perfect alignment, at the cost of less space for the subject itself. Trade-offs, bestie, it's giving ✨balance✨.
  • cross-filter-seq (boolean, default true) — when set, cross-posted articles will be presented in the first possible group, i.e. according to the current presentation sequence (cross-post filtering on sequence, iykyk). The article is automatically marked read in the other cross-posted groups — unless you unsubscribe to the first group in which it was shown before reading the other groups. Likewise, it's sufficient to leave the article unread in the first group to keep it for later handling. 🫶
    • If it's not set, cross-postings are shown in the first group occurring on the Newsgroups: line which the user subscribes to — i.e. you let the poster decide which group is most appropriate to read his posting. (Their call, their main character moment. 💀)
  • cross-post (boolean, default false) — normally, nn will only show cross-posted articles in the first subscribed group on the Newsgroups: line. But when cross-post is set, nn will show cross-posted articles in all subscribed groups to which they are posted. 🌈
  • cross-post-limit N (integer, default 0) — if this variable is set to a value other than 0, then any articles posted to more than N newsgroups are automatically skipped. A value of 5 is pretty good for discarding ``spam'' articles. 🚫🍓
  • data-bits bits (integer, default 7) — when set to 7, nn will display characters with the 8th bit set using a meta-notation M-7bit-char. If set to 8, those characters are sent directly to the screen (unless monitor is set). Setting the charset variable also sets this variable to the default bit width of the character set. 💅
    • It also controls whether keyboard input is 7 or 8 bits, and thus whether key maps contain 127 or 255 entries. See the key mapping section for more details.
    • If the charset has value "unknown", the value of data-bits also determines whether nn allows 8-bit characters in the body of articles being posted and letters being mailed (this is normally determined directly by the charset variable).
  • date (boolean, default true) — if set, nn will show the article posting date when articles are read. 📅
  • debug mask (integer, default 0) — look in the source if you are going to use this. 😌 That's it. That's the whole description. Good luck bestie.
  • decode-header-file file (string, default "Decode.Headers") — the name of the file in which the header and initial text of articles decoded with the :decode command is saved. Unless the file name starts with a /, the file will be created in the same directory as the decoded files. Note: the information is not saved if this variable is not set. 🙈
  • decode-skip-prefix N (integer, default 2) — when non-null, the :decode command will automatically skip up to N characters at the beginning of each line to find valid uuencoded data. This lets nn automatically decode (multi-part) postings which are both uuencoded and packed with shar. Multitasking icon. 🔥
  • default-distribution distr (string, default "world") — the distribution to use as the default suggestion when posting articles using the follow and post commands, if the corresponding follow-distribution or post-distribution variable contains the default option. 🌍
  • default-kill-select [1]days (number, default 30) — specifies the default action for the K {kill-select} command if the first prompt is answered by return. It contains the number of days to keep the kill or select entry in the kill file (1-99 days). And here's the lil trick: if it has the value days+100 (e.g. 130), it denotes that the default action is to select rather than kill on the subject, for the specified period. 👑
  • default-save-file file (string, default +$F) — the default save file used when saving articles in news groups where no save file has been specified in the init file (either in a save-files section or in the presentation sequence). It can also be specified using the abbreviation + as the file name when prompted for a file name, even in groups that have their own save file. 🎀
  • delay-redraw (boolean, default false) — normally, nn will redraw the screen after extended commands (:cmd) that clear the screen. When delay-redraw is set, nn will prompt for another extended command instead of redrawing the screen (hit return to redraw). Efficient queen. ✨
  • echo-prefix-key (boolean, default true) — when true, hitting a prefix key (see the section on key mapping below) will cause the prefix key to be echoed in the message line, to indicate that another key is expected. 🦋
  • edit-patch-command (boolean, default true) — when true, the :patch command will show the current patch-command and give you a chance to edit it before applying it to the articles. 💅
  • edit-print-command (boolean, default true) — when true, the print command will show the current printer command and give you a chance to edit it before printing the articles. Otherwise the articles are just printed using the current printer command. 🖨️
  • edit-response-check (boolean, default true) — Okay so when you're editing a response to an article, it literally makes no sense to send the initial file nn prepped for you completely untouched, bestie, because it's either empty or it's just the included material and nothing of you 💅. So when this is set, if you bail out of the editor without having changed the file, the response action just auto-aborts, no confirmation, no drama, periodt.
  • edit-unshar-command (boolean, default false) — When true, the :unshar command lowkey shows you the current unshar-command and gives you a whole moment to edit it before it gets applied to the articles 👑
  • editor command (string, default not set) — Set this and it overrides whatever your current EDITOR environment variable is saying when you're editing responses and new articles. It's giving main character energy, honestly ✨
  • embedded-header-escape string (string, default '~') — When you save an article to a file, header lines that are chillin' embedded in the body of the article get escaped using this string, so nn can split the folder correctly afterwards. If this variable isn't set? Header lines get zero escaping, fr fr.
  • enter-last-read-mode mode (integer, default 1) — Normally nn remembers which group was active when you quit, and offers to jump straight to that group next time you start. This variable controls all that. The mode values it recognizes:
    • 0: Ignore the remembered group (r.g.).
    • 1: Enter r.g. if the group is unread (with user confirmation).
    • 2: Enter r.g. or the first unread group after it in the sequence (with confirmation).
    • 3: Enter r.g. if the group is unread (no confirmation).
    • 4: Enter r.g. or the first unread group after it in the sequence (no confirmation).
  • entry-report-limit articles (integer, default 300) — Normally nn just moves the cursor to the upper left corner of the screen while it's reading articles from the database on entry to a group. But for big groups that can take more than a fraction of a second 😭, so nn can report what it's doing. If it has to read more articles than this number, nn tells you which group and how many articles it's reading.
  • erase-key key (key, default tty erase key) — The key that erases the last input character when nn is prompting you for a string, like a file name. Your backspace bestie 🫶
  • expert (boolean, default false) — Set this and nn uses slightly shorter prompts (like, it won't tell you that ? gives you help) and is a bit less chatty in a few other cases (like it won't remind you that posted articles aren't available instantly). Minimalist icon behavior 💅
  • expired-message-delay pause (integer, default 1) — If a selected article turns out to have been expired, nn normally gives you a message about it and sleeps for however many seconds this variable says. Set it to zero and you still get the message, just no nap afterwards. Set it to -1 and the message doesn't show up at all 🙈
  • flow-control (boolean, default true) — When set, nn turns on xon/xoff flow-control before writing big amounts of text to the screen. This is supposed to guard against output lossage, BUT 💀 in some network configurations it's had the opposite effect, losing several lines of output. Heads up! This variable is always true on systems with CBREAK capabilities that can do single character reads without disabling flow control.
  • flush-typeahead (boolean, default false) — When true, nn flushes typeahead before reading commands from the keyboard. It will not flush typeahead while reading parameters for a command, like file names and stuff.
  • folder directory (string, default ~/News) — The full pathname of the folder directory, which is what replaces the + in folder names. It gets initialized from the FOLDER environment variable if it's not set in the init file.
  • folder-format-check (boolean, default true) — When saving an article with a full or partial header into an existing folder, nn checks the format of the folder so it can append the article in the proper format. If this variable isn't set, folders are just assumed to be in the format specified via the mmdf-format and mail-format variables, and articles get saved in that format with zero checking. Otherwise, the *-format variables are only used to figure out the format for new folders.
  • folder-save-file file (string, default not set) — The default save file used when you're saving articles from a folder.
  • follow-distribution words (string, default see below) — This one controls how the Distribution: header gets constructed for a follow-up to an original article. Its value is a list of words picked from:
[ [ always ] same ] [ ask ] [ default | distribution ]

And it's interpreted in two steps:

  • First, the default distribution gets determined. If same is specified and the original article has a Distribution: header, that header is used. Else if default is specified (or distribution is omitted), the value of default-distribution is used. And finally, if only a distribution (any word) is specified, that's used as the default.
  • Then, if ask is specified, you'll be asked to confirm the default distribution or provide another one. However, if always (and same) is specified, and the default came from the original article's distribution, the original distribution is used with no confirmation. The default value of follow-distribution is always same default, i.e. use either the original distribution or the default-distribution with no confirmation either way. ✨
  • from-line-parsing strictness (integer, default 2) — Specifies how strict nn has to be when parsing a "From " line in a folder to recognize it as a mail format message separator line. The strictness values decide whether a line starting with "From " is recognized as a separator line:
    • 0: Always.
    • 1: Line must have at least 8 fields.
    • 2: Line must contain a valid date and time (ctime style).
  • fsort (boolean, default true) — When set, folders get sorted alphabetically by the subject (and age). Otherwise, articles in a folder show up in the sequence they were saved in.
  • guard-double-slash (boolean, default false) — Normally, when you're entering a file name, typing two slashes // in a row (or following a slash with a plus /+) makes nn erase the whole line and replace it with the / (or +). But on some systems two slashes are used in network file names, so on those systems you can set guard-double-slash — that makes nn require three slashes in a row to clear the input 👑
  • header-lines list (string, no default) — When set, it decides the list of header fields shown when an article is read, instead of the normal one line header showing the author and subject. Full description lives in the section on Customized Article Headers below, iykyk.
  • help-key key (key, default ?) — The key that ends the current completion and gives you a list of possible completions for the next component when nn is prompting for a string, like a file name.
  • ignore-re (boolean, default false) — If set, articles with subjects you've already seen in a previous invocation of nn or another newsreader — and not auto-selected — get automatically killed. A great way to read even less news! 😭 No cap.
  • ignore-xon-xoff (boolean, default false) — Normally nn ignores ^S and ^Q in the input from the terminal (if they're not handled in the tty driver). Setting this variable treats those characters as normal input instead.
  • include-art-id (boolean, default false) — The first line in a response with included material normally reads "...somebody... writes:" with no reference to the specific article the quotation came from (that's found in the References: line). When this variable is set, the line also includes the article id of the referenced article: "In ...article... ... writes:" ✨
  • include-full-header (boolean, default false) — When set, the mail (M) command always includes the full header of the original article. If it's not set, it only includes the header when the article is forwarded without being edited.
  • include-mark-blank-lines (boolean, default false) — When set, the included-mark goes on blank lines in included articles too. Otherwise, blank lines are left blank (which makes it easy to delete whole paragraphs with d} in vi and C-@ M-] C-W in emacs 🎀).
  • included-mark string (string, default ">") — This string gets prefixed to all lines in the original article that are included in a reply or a follow-up. (Look, now you can change it, but please don't 🙏. Lines with a mixture of prefixes like
   : orig-> <> } ] #- etc.

are very difficult to comprehend. Let's all use the standard folks! (And hack inews if it's the 50% rule that bothers you.))

  • inews shell-command (string, default "INEWS_PATH -h") — The program nn invokes to deliver an article to the news transport. It gets a complete article including a header containing the newsgroups the article is to be posted to. See also inews-pipe-input. It is not used when cancelling an article! 💀
  • inews-pipe-input (boolean, default true) — When set, the article to be posted gets piped into the inews program. Otherwise, the file containing the article is given as the first (and only) argument to the inews command.
  • initial-newsrc-file file (string, default '.defaultnewsrc') — bestie this is the starter pack .newsrc for brand new users 💖 You can give it a whole full path name, or, like the default, just a bare file name and nn will go hunting for it in a few spots: the standard news lib directory (iykyk, so it can be shared with other news readers), nn's own lib directory, and the database directory. And here's the tea: any group that is not in that initial .newsrc gets automatically unsubscribed — but only if new-group-action is set to a value that lets unsubscribed groups be left out of .newsrc. Periodt.
  • keep-backup-folder (boolean, default false) — turn this on and the backup folder (peep backup-folder-path) that gets made when you remove deleted articles from a folder... stays. It does not get yeeted. 💅
Heads up though: a backup folder is not created at all if all articles are removed from a folder. So don't come for me when there's nothing to keep. 😭
  • keep-unsubscribed (boolean, default true) — when set, your unsubscribed groups stay chillin' in .newsrc. Flip it off and nn will automatically remove all the unsubscribed ones from .newsrc if tidy-newsrc is set. Also go look at unsubscribe-mark-read. 🌸
  • kill (boolean, default true) — if this is set, nn does automatic kill and selection based on the kill file. The whole murder-board thing, iconic. 🔥
  • kill-debug (boolean, default false) — set it and nn spills a whole trace of the auto-kill/select process the moment you enter a group. It turns itself off automatically if you hit q as your answer to a "hit any key" prompt while the debug output is running. Self-care, honestly. ✨
  • kill-key key (key, default tty kill key) — the key that deletes the line you're currently typing when nn is prompting you for a string, like a file name. That lil eraser bestie. 🧚
  • kill-reference-count N (integer, default 0) — when this is non-zero, every article that has N or more references on the References: line (which corresponds to the number of >>'s on the menu line) gets auto-killed — unless it was auto-selected (or preserved) by an entry in the kill file. Ngl, you probably shouldn't set this globally for all groups, but you can set it per-group via the entry macros. 👑
  • layout number (integer, default 1) — sets the menu layout. The argument has to be a number between 0 and 4. No vibes-based arguments allowed. 💀
  • limit max-articles (integer, default infinite) — caps the maximum number of articles shown in each group at max-articles. By default it shows all unread articles, no matter how many there are (chaos, honestly). Set this and only the most recent max-articles articles get presented — but all the articles will still be marked as read. Super useful if you want to get up-to-date quickly after you haven't read news for a longer period. The catch-up slay. 🦋
  • lines lin (integer, default screen height) — this variable holds the screen height, i.e. the number of lines. That's it, that's the variable. 💜
  • long-menu (boolean, default false) — set it and nn will not put an empty line after the header line, and not put an empty line before the prompt line. Boom, two extra menu lines for you. Free real estate. 🎀
  • macro-debug (boolean, default false) — set it and nn traces the execution of all macros. Before each command or operation inside a macro runs, it shows you the name of the command, or the input string, or the key stroke, down at the bottom of the screen. Like subtitles for your macros. ✨
  • mail file (string, default not set) — file has to be a full path name of a file. Define it and nn will check for arrival of new mail every minute or so by looking at that specified file. 👀
  • mail-alias-expander program (string, default not set) — when set, aliases used in mail responses can get expanded by the program you name. The program gets the completed response in a file as its only argument, and the aliases should be expanded directly in this file (obviously the program can use temporary files and other means to expand the aliases, as long as the result ends up stored in the provided file).
Notice: currently there are no alias expanders delivered with nn. So you're on your own, bestie. 🫶 Warning: errors in the expansion process may lead to the response not being sent. 💀 Not the ghosting you were going for.
  • mail-format (boolean, default false) — when set, nn saves articles in a format that's compatible with normal mail folders. Unless folder-format-check is false, this is only used to specify the format used when new folders are created. And this variable gets ignored entirely if mmdf-format is set. Priority drama. 💅
  • mail-header headers (string, default not set) — the headers string specifies one or more extra header lines (separated by semi-colons ;) that get added to the header of mail sent from nn using the reply and mail commands. For example:
set mail-header Reply-To: storm@texas.dk;Organization: TI - DK

To include a semi-colon ; in a header, precede it with a backslash (which has to be doubled because of the conventions for entering strings). Ungovernable punctuation, fr fr. 😭

  • mail-record file (string, default not set) — file must be a full path name. Define it and every reply and all mail gets saved in this file in standard mailbox format — meaning you can use your favourite mailer (and nn!) to look at the file. Receipts. 🧾✨
  • mail-script file (string, default not set) — set it and nn uses the file you name instead of the standard aux script when executing the reply and mail commands. Custom aux script era. 🎀
  • mailer shell-command (string, default REC_MAIL) — the program nn invokes to deliver a message to the mail transport. It gets handed a complete mail message, header included, with the recipient's address in there. Also see mailer-pipe-input. 📮
  • mailer-pipe-input (boolean, default true) — when set, the message to be sent gets piped into the mailer program. If not set, then the file containing the message is given as the first (and only) argument to the mailer command instead. Pick your lane. 🔥
  • marked-by-next-group N (integer, default 0) — specifies how many (unmarked) articles on the menu get marked seen by the N {next-group} command in selection mode. Check marked-by-read-skip for the possible values of N. 👑
  • marked-by-read-return N (integer, default 0) — same deal, but for how many (unmarked) articles get marked seen by the Z {read-return} command in selection mode. Again, see marked-by-read-skip for possible values of N. 🌈
  • marked-by-read-skip N (integer, default 4) — how many (unmarked) articles get marked seen by the X {read-skip} command in selection mode. The values of N it recognises are:
    1. No articles are marked seen
    2. Current page is marked seen
    3. Previous pages are marked seen
    4. Previous and current pages are marked seen
    5. All pages are marked seen
  • mark-overlap (boolean, default false) — when set, nn draws a line (using the underline capabilities of the terminal, if it has them) to show where the overlap ends. See the overlap variable. 💅
  • mark-overlap-shading (boolean, default false) — when set, nn shades the overlapping lines (again, see overlap) using whatever attributes shading-on and shading-off define — or, if those aren't set, with the underline attribute. This is typically used to give overlapping lines a different colour on terminals that can do that. Aesthetic and functional. 🦋
  • menu-spacing mode (integer, default 0) — when mode is a non-zero number as described below, nn adds blank lines between the lines on the menu, which boosts readability at the cost of fitting fewer articles on each page. The values of mode it recognises are:
    1. Don't add blank lines between menu lines.
    2. Add a blank line between articles with different subjects.
    3. Add a blank line between all articles.
  • merge-report-rate rate (integer, default 1) — when nn is invoked with the -m option (directly or via nngrap), a status report of the merging process is displayed and updated on screen every rate seconds. The report contains the time used so far and an estimate of the time needed to finish the merge. Progress bar but make it wordy. ✨
  • message-history N (integer, default 15) — the maximum number, N, of older messages you can recall with the ^P {message} command. Memory lane has a cap, bestie. 🧠
  • min-window size (integer, default 7) — when the window variable is not set, nn will clear the screen to preview an article if there are fewer than size unused lines at the bottom of the menu screen. Vibe check on your leftover space. 👀
  • mmdf-format (boolean, default false) — when set, nn saves articles in MMDF format. Unless folder-format-check is false, this is only used to specify the format used when new folders are created. 📁
  • monitor (boolean, default false) — when set, nn shows all characters in received messages using a cat -v-like format. Otherwise, only printable characters are shown (that's the default). See the invisible, bestie. 💀
  • motd (boolean, default true) — when set, nn displays the message of the day on start-up if it has changed since it was last shown. That message is taken from the file "motd" in the lib directory. You can also show it (again!) with the :motd command. 🌸
  • multi-key-guard-time timeout (integer, default 2) — when nn reads a multi-key sequence from the keyboard, it expects the characters making up that multi-key to arrive "quickly" one after another. When a partial multi-key sequence has been read, nn waits (at least) timeout tenths of a second for each of the following characters to show up and complete the sequence. If the multi-key sequence doesn't get completed in that window, nn just reads the partial sequence as individual characters instead. That's how you can still use, say, the Esc key on a terminal with vt100-style arrow keys. And when nn is being used over an rlogin connection, you may have to increase the timeout to get reliable recognition of multi-keys. Type slower, type happier. 🐢💜

  • new-group-action action (integer, default 3) — bestie this one decides how nn treats brand-new groups 💖 it's an integer, and here's the whole vibe menu. Heads up tho: some actions (the ones with a *) only work when keep-unsubscribed is set, because a group showing up in .newsrc is literally the only way nn clocks it as an old group:
    • 0) Straight up ignore groups that aren't in .newsrc. Which obviously includes new groups, so you have to explicitly add any new group you actually care about (by editing the .newsrc file, or using the G menu command and then subscribing to the group). When NNTP is being used, this setting stops the active.times data from being read off the server — lowkey a slay when you're on a slow link, since that data can often be hundreds of KBytes long.
    • 1*) Groups not in .newsrc are considered new, and get inserted at the beginning of the .newsrc file.
    • 2*) Groups not in .newsrc are considered new, and get appended to the end of the .newsrc file.
    • 3) New groups are recognized via a time-stamp saved in the file .nn/LAST and in the database, i.e. it does not depend on the groups currently in .newsrc. The new groups are automatically appended to .newsrc with subscription. Old groups not present in .newsrc get considered unsubscribed. ✨
    • 4) Same as 3, but the user is asked to confirm that the new group should be appended to .newsrc. If you reject it, the group won't be appended to .newsrc, and thus gets regarded as unsubscribed.
    • 5) As 4, except the information is stored in a format compatible with the rn news reader (.rnlast). This needs to be tested! 😭
  • new-style-read-prompt (boolean, default true) — when set, the reading mode prompt line includes the group name and the number of selected articles in the group. Iconic little quality-of-life upgrade fr.
  • news-header headers (string, default not set) — the headers string specifies one or more extra header lines (separated by semi-colons ;) which get added to the header of articles posted from nn using the follow and post commands. Peep mail-header for an example 🫶
  • news-record file (string, default not set) — save file for follow-ups and postings. Same rules and format as the mail-record variable.
  • news-script file (string, default not set) — when set, nn will use the specified file instead of the standard aux script when executing the follow and post commands.
  • newsrc file (string, default "~/.newsrc") — the file nn uses to register which groups and articles have been read. The default setting corresponds to the .newsrc file used by other news readers. Notice that nn release 6.4 onwards does allow individual articles to be marked unread, and some articles marked unread, and thus no longer messes up .newsrc for other news readers! 🎀 Also see nntp-server.
  • nn-directory directory (string, default "~/.nn") — it only makes sense to set this variable on the command line, e.g. "nn-directory=$HOME/.nn2" since it gets looked at before the init file is read. It must be set to a full pathname. Usually set when you're using multiple servers; see newsrc above and nntp-server below.
  • nntp-cache-dir directory (string, default "~/.nn") — when NNTP is used, nn needs to store articles temporarily on disk. This variable says which directory nn will use to hold these files. The default value may be changed during configuration. This variable can only be set in the init file.
  • nntp-cache-size size (integer, default 10, maximum 10) — the number of temporary files in the nntp cache. The default and maximum values may be changed during configuration.
  • nntp-debug (boolean, default false) — when set, a trace of the nntp related traffic is displayed in the message line on the screen. 👀
  • nntp-forceauth (boolean, default false) — when set, forces nn to authenticate, even when the nntp server doesn't request it.
  • nntp-password (string, default not set) — the users nntp password.
  • nntp-server hostname or filename (string) — it only makes sense to set this variable on the command line, e.g. "nntp-server=news.some.domain", since it gets looked at before the init file. If you use multiple servers, you probably want to set the nn-directory and newsrc variables on the command line to alternate names as well, since some of the data files are server dependent.
  • nntp-user (string, default not set) — the users nntp username.
  • old [max-articles] (integer, default not set) — when old is set, nn will present (or scan) all (or the last max-articles) unread as well as read articles. While old is set, nn will never mark any unread articles as read. 💅
  • old-packname (boolean, default false) — when set, nn display names identically to nn-6.6.5 (and earlier). Only set this if you have a large number of entries in your killfile that no longer work due to the new behaviour. Note that in the long run, this option will go away, so it's best to update your killfile rather than set this.
  • orig-to-include-mask N (integer, default 3) — when replying to an article, nn will include some of the header lines which may be used to construct a proper mail address for the poster of the original article. These addresses are placed on Orig-To: lines in the reply header and will automatically be removed before the letter is sent. This variable specifies which headers from the article are included; its value N is the sum of the following values:
    • 1: Reply-To:
    • 2: From:
    • 4: Path:
  • overlap lines (integer, default 2) — the number of overlapping lines from one page to the next when paging through an article in reading mode. The last line from the previous page will be underlined if the terminal has that capability.
  • pager shell-command (string, default $PAGER) — this is the pager used by the :admin command (and nnadmin) when it executes certain commands, e.g. grepping in the Log file.
  • patch-command shell-command (string, default "patch -p0") — this is the command which is invoked by the :patch command.
  • post-distribution words (string, default see below) — this variable controls how the Distribution: header is constructed when posting an original article. Its value is a list of words selected from the following list:
[ ask ] [ default | distribution ]

This is interpreted in two steps:

  • First the default distribution is determined. If default is specified (or distribution is omitted), the value of default-distribution is used. Otherwise, the specified distribution (any word) is used as the default.
  • Then if ask is specified, the user will be asked to confirm the default distribution or provide another distribution.

The default value of post-distribution is ask default, i.e. use the default-distribution with confirmation from the user.

  • preview-continuation cond (integer, default 12) — this variable determines on what terms the following article should be automatically shown when previewing an article, and the next-article command is used, or continue is used at the end of the article. The following values can be used:
    • 0 — never show the next article (return to the menu).
    • 1 — always show the next article (use 'q' to return to the menu).
    • 2 — show the next article if it has the same subject as the current article, else return to the menu.

The value should be the sum of two values: one for the action after using continue on the last page of the article, and one for the action performed when the next-article command is used multiplied by 10.

  • preview-mark-read (boolean, default true) — when set, previewing an article will mark the article as read.
  • previous-also-read (boolean, default true) — when set, going back to the previously read group with P {previous} will include articles read in the current invocation of nn even if there are still unread articles in the group.
  • print-header-lines fields (string, default "FDGS") — specifies the list of header fields that are output when an article is printed via the :print command and print-header-type is 1 (short header). The fields specification is described in the section on Customized Article Headers below.
  • print-header-type N (integer, default 1) — specifies what kind of header is printed by the :print command, corresponding to the three save-* commands: 0 prints only the article body (no header), 1 prints a short header, and 2 prints the full article header.
  • printer shell-command (string, default is system dep.) — this is the default value for the print command. It should include an option which prevents the spooler from echoing a job-id or similar to the terminal to avoid problems with screen handling (e.g. lp -s on System V).
  • query-signature (boolean, default ...) — will cause nn to require confirmation before appending the .signature file to out-going mail or news if the corresponding append-sig-... variable is set. 🫶
  • quick-count (boolean, default true) — when set, calculating the total number of unread articles at start-up is done by simple subtracting the first unread article number from the total number of articles in each group. This is very fast, and fairly accurate but it may be a bit too large. If not set, each line in .newsrc will be interpreted to count every unread article, thus giving a very accurate number. This variable is also used by nncheck.
  • quick-save (boolean, default false) — when set, nn will not prompt for a file name when an article is saved (unless it belongs to a folder). Instead it uses the save file specified for the current group in the init file or the default save file. ⚡
  • re-layout N — (integer, default 0) so like, on the menu, nn will slap a bunch of <cyan>></cyan>s in front of the subject, and the number of them matches the number of references on the References: line. Obsessed. But if you wanna switch up that prefix, set this variable:
    • 0: one <cyan>></cyan> per reference is shown (this is the default, bestie).
    • 1: a single <cyan>></cyan> shows up if the Subject contains Re:.
    • 2: the number of references shows as <cyan>n></cyan>.
    • 3: a single Re: is shown.
    • 4: if any references use layout 0, else layout 1.
  • re-layout-read N — (integer, default -1) okay so when the header-lines variable isn't set, or it contains the "*" field specifier, a line kinda like the menu line gets used as the header of the article in reading mode — sender's name AND the article's subject, the whole vibe. When this variable is negative, the subject on that header line gets prefixed according to the re-layout variable. Otherwise? It defines the format of the "Re:" prefix used instead of the re-layout used on the menu. Slay.
  • read-return-next-page — (boolean, default false) when set, the Z {read-return} command returns you to the next menu page instead of the current one. cute.
  • record file — (string, no default) setting this pseudo variable sets both the mail-record and the news-record variables to the pathname you specify. two birds, one variable ✨
  • repeat — (boolean, default false) when set, nn will not eliminate duplicated subject lines on menus. and the manpage literally says: (I cannot imagine why anyone should want that, but....) 😭 no notes, truthfully.
  • repeat-group-query — (boolean, default false) when set, invoking nn with the -g option will always repeat the query for a group to enter until you quit explicitly. it's the same as setting the -r option permanently, fr fr.
  • report-cost — (boolean, default true) bestie this one gets ignored unless nn is running with accounting enabled (see nnacct). When set, nn reports the cost of the current session and the total on exit. 💸
  • response-check-pause pause — (integer, default 2) how many seconds to wait after posting an article to see whether the action might have failed. and lowkey important: some commands run in the background and may not have finished during this window, so even when nn says "Article posted", it may still fail — in which case you get informed via mail. 😭 the audacity.
  • response-default-answer action — (string, default "send") the default action taken when you hit return at the "response action" prompt. the options are abort, edit, send, view, write. If it's unset, no default action is defined at all. periodt.
  • retain-seen-status — (boolean, default false) normally, seen articles just get unread again the next time you enter the group (unless they were marked read by auto-junk-seen). If retain-seen-status is set, the seen attribute on the articles survives to the next time the group is entered. > ⚠️ not recommended, bestie — it may result in very large select files. 💀
  • retry-on-error times — (integer, default 0) when set, nn tries the specified number of times to open an article before reporting that the article doesn't exist any more. this may be necessary in some network environments. we love a resilient queen. 🫶
  • save-closed-mode mode — (integer, default 13) so when you're saving an article in selection mode (like, picking it from the menu), nn just saves the specified article if the article's subject is open. When the selected menu entry is a closed subject, this variable decides how many articles among the closed articles get saved:
    • 0: save root article (the one on the menu) only
    • 1: save selected articles within subject
    • 2: save unread (excl selected) articles within subject
    • 3: save selected+unread articles within subject
    • 4: save all articles within subject

and here's the plot twist 👑 — if you add 10 to any of those values, nn will not save the selected subject immediately. Instead it asks which articles to save, using the above value as the default answer. iconic.

  • save-counter format — (string, default "%d") this is the printf-format nn uses to create the substitution string for the trailing * in save file names. You can set it to more complex formats if you like, but be sure it produces different strings for different numbers. An alternative format that seems to be popular is ".%02d". 🎀
  • save-counter-offset N — (integer, default 0) normally, file names created with the part.* form substitute the * with successive numbers starting from one. Setting this variable makes those numbers start from N+1. math girlies rise. ✨
  • save-header-lines fields — (string, default "FDNS") the list of header fields saved when an article is saved via the O {save-short} command. The fields specification is described in the section on Customized Article Headers below. iykyk.
  • save-report — (boolean, default true) when set, a message reporting the number of lines written shows after saving an article. Since messages are shown for a few seconds, this may slow down the saving of many articles (e.g. using the S* command). fair warning bestie 🍓
  • scroll-clear-page — (boolean, default true) determines whether nn clears the screen before showing each new page of an article. the eternal question 💅
  • scroll-last-lines N — (integer, default 0) normally, nn shows each new page of an article from the top of the screen (with proper marking of the overlap). When this variable is set to a negative value, nn scrolls the text of the new pages from the bottom of the screen instead. If it's set to a positive value, nn shows pages from the top as usual, but switches to scrolling when there are less than the specified number of lines left in the article. choose your own adventure fr. 🌈
  • select-leave-next — (boolean, default false) when set, you'll be asked whether to select articles with the leave-next attribute on entry to a group with left over articles. consent but for sorting ✋
  • select-on-sender — (boolean, default false) specifies whether the find (=) command in article selection mode will match on the subject or the sender. pick a lane 🦋
  • shading-on code... — (control string, default not set) the escape code sent to the terminal to cause "shading" of the following output to the screen. This is used if the mark-overlap-shading is set, and by the + attribute in the header-lines variable.
  • shading-off code... — (control string, default not set) the escape code sent to the terminal to turn off the shading defined by shading-on. Shading will typically be done by changing the foreground colour, e.g.
on term ti924-colour
     set shading-on  ^[ [ 3 2 m
     set shading-off ^[ [ 3 7 m
     set mark-overlap-shading
     unset mark-overlap
end
  • shell program — (string, default $SHELL) the shell program used to execute shell escapes. yeah she runs the whole show.
  • shell-restrictions — (boolean, default false) when set (in the init file), nn will not allow the user to invoke the shell in any way, including saving on pipes. It also prevents the user from changing certain variables containing commands. > 🔒 hard mode. no escaping the escape, bestie.
  • show-purpose-mode N — (integer, default 1) normally, nn shows the purpose of a group the first time it's read, provided a purpose is known. Setting this variable changes that behaviour like so:
    • 0: never show the purpose.
    • 1: show the purpose for new groups only.
    • 2: show the purpose for all groups.

When NNTP is being used, a setting of 0 prevents the newsgroups purpose data from being read from the server — this can be helpful when using a slow link, since the data can often be hundreds of KBytes long. 😭 the size of it.

  • sign-type — (string, default pgp) what program nn uses to sign messages via the Sign command. Only pgp and gpg are currently valid. cryptographic girlypop energy 🔐
  • silent — (boolean, default false) when set, nn won't print the logo or "No News" if there are no unread articles. Only useful to set in the init file or with the -Q option. peace and quiet, deserved. 🙈
  • slow-mode — (boolean, default false) when set, nn cuts down on screen output to give better response time at low speed. Normally nn uses standout mode (if possible) to mark selected articles on the menu, but with slow-mode set, nn just puts an asterisk * next to the article identifier on selected articles. Also, when slow-mode is set, nn avoids redrawing the screen in these cases: after a goto-group command an empty menu is shown (hit space to make it appear), and after responding to an article, only the prompt line is shown (use ^L to redraw the screen). To avoid redrawing the screen after an extended command, set the delay-redraw variable as well. efficiency queen 💅
  • slow-speed speed — (integer, default 1200) if the terminal is running at this baud rate or lower, the on slow (see the section on init files) condition will be true, and the on fast will be false (and vice-versa). retro tech moment 📼
  • sort — (boolean, default true) when set, nn sorts articles according to the current sort-mode on entry to a group. Otherwise, articles are presented in order of arrival. If not set on entry to a menu for merged groups, the articles from each group will be kept together on the menu. If sort is unset while merged groups are presented on the menu, the articles get reordered by local article number (which may not keep articles from the same group together). chaos but make it organised ✨
  • sort-mode mode — (integer, default 1) the default sort algorithm used to sort the articles on entry to a news group. It's a numeric value corresponding to one of the sorting methods described in connection with the :sort command:
    • 0 - arrival (ordered by article number)
    • 1 - subject (subjects ordered after age of first article)
    • 2 - lexical (subjects in lexicographical order)
    • 3 - age (articles ordered after posting date only)
    • 4 - sender (articles ordered after sender's name)

pick your fighter, bestie 👑

  • spell-checker shell-command — (string, default not set) bestie, set this and your replies can get spell-checked through the (i)spell action 💅. The command that does the spelling gets the file holding the whole entire article — header included — as its only argument. And heads up: if your spell checker is capable of fixing the mistakes, it has to write those changes directly into that same file. No middleman.
  • split — (boolean, default true) turn this on and digests get automatically and silently split into sub-articles, which then get handled transparently like normal articles, no cap ✨. Turn it off and a digest shows up as one big article instead — you can still split it on demand yourself with the G command.
  • stop lines — (integer, default not set) when stop is set, nn will only show you the first lines lines of each article before it prompts you to continue. This is giving slow terminal / modem line realness — it lets you peek at the first few lines of longer articles (and skip the rest with the n command). Perfect for those days when your connection is doing the absolute most 🐌.
  • subject-match-limit length — (integer, default 256) two subjects count as identical if their first length characters match. ⚠️ Setting this uncritically to a low value may cause unexpected results! Like, be so serious about this one.
  • subject-match-offset offset — (integer, default 0) set it to a positive number and that many characters at the beginning of the subject get ignored when nn compares subjects for ordering and equality purposes. Lowkey a glow-up for your sorting ✨.
  • subject-match-parts — (boolean, default false) when set, two subjects are considered equal if they're identical up to the first (differing) digit. Together with the subject-match-offset variable, this is the move in source groups where the subject often has a format like:
vXXXXXX: Name of the package (Part 01/04)

Set subject-match-offset to 8 and subject-match-parts to true and nn will consider all four parts of the package as having the same subject (and thus they're selectable with *). Obsessed 💖.

Notice that changing the subject-match-... variables manually will not have an immediate effect. To reorder the menu, you have to do an explicit :sort command. These variables are mainly intended to be set using the :local command in on entry macros for source and binary groups (entry macros are evaluated before the menu is collected and sorted).

  • subject-match-minimum characters — (integer, default 4) when set to a positive number, that many characters at the beginning of the subject must match before the subject-match-parts option comes into affect. This matters, because the part matching causes the rest of the line to be ignored after the first digit pair is discovered. And it begins after any subject-match-offset has been applied. Slay.
  • suggest-default-save — (boolean, default true) when set, nn will present the default-save-file when it's prompting you for a save file name in a group that doesn't have a specific save file, or folder-save-file when you're saving from a folder. When it's not set, no file name is presented, and to use the default save file you must specify a single +. Periodt.
  • tidy-newsrc — (boolean, default false) when set, nn will automatically remove lines from .newsrc that represent groups not found in the active file, or unsubscribed groups — but only if keep-unsubscribed is not set. Clean girl aesthetic for your newsrc 🧹✨.
  • time — (boolean, default true) when set, nn shows the current time in the prompt line. Genuinely useful on systems that don't have a sysline (1) utility. ⏰
  • trace-folder-packing — (boolean, default true) when set, a trace of the retained and deleted messages gets printed when a folder is rewritten.
  • trusted-escape-codes codes — (string, default none) set this to a list of one or more characters and nn will trust and output escape characters in an article if the escape is followed by one of the characters in that list. For example, to switch to or from kanji mode, control codes like "esc $" and "esc ( J" may be present in the text. To allow these codes, use the following command:
set trusted-escape-codes ($

You can also set it to all to pass all escape codes through to the screen. Notice that nn thinks all characters (including esc) output to the screen occupy one column. 💀

  • unshar-command shell-command — (string, default "/bin/sh") this is the command which is invoked by the unshar command.
  • unshar-header-file file — (string, default "Unshar.Headers") the name of the file in which the header and initial text of articles unpacked with the :unshar command is saved. Unless the file name starts with a /, the file will be created in the same directory as the unpacked files. The information is not saved if this variable is not set. Setting it to "Unshar.Result" will cause the headers and the results from the unpacking process to be merged in a meaningful way (unless mmdf-format is set). 🫶
  • unsubscribe-mark-read — (boolean, default true) when set, unsubscribing to a group automatically marks all current articles read; this is recommended to keep the size of .newsrc down. Otherwise, unread articles in the unsubscribe groups are kept in .newsrc. And if keep-unsubscribed is false, this variable has no effect at all.
  • update-frequency — (integer, default 1) specifies how many changes need to be done to the .newsrc or select files before they get written back to disk. The default setting causes .newsrc to be updated every time a group has been read.
  • use-editor-line — (boolean, default true) most editors accept arguments of the form:
editor [-arguments] +n filename

where editor is the name of the editor, and n is the line number to put the cursor upon entering the file. If use-editor-line is false, it will not add the "+n" to the arguments.

  • use-path-in-from — (boolean, default false) when mail-format is set, saved articles will be preceded by a specially formatted "From " line:
From origin date

Normally, the origin will be the name of the news group where the article appeared, but if use-path-in-from is set, the contents of the "Path:" header will be used as the origin.

  • use-selections — (boolean, default true) when set, nn uses the selections and other article attributes saved last time nn was used. If not set, nn ignores the select file entirely.
  • visible-bell — (boolean, default true) when set, nn will flash the screen instead of "ringing the bell" if the visible bell (flash) capability is defined in the termcap/terminfo database. So much less jarring, bestie 🌸.
  • window size — (integer, default not set) when set, nn will reserve the last size lines of the menu screen for a preview window. If not set, nn will clear the screen to preview an article if there are less than min-window lines at the bottom of the screen. As a side effect, it can also be used to reduce the size of the menus, which may be useful on slow terminals.
  • word-key key — (key, default ^W) the key which erases the last input component or word when nn is prompting you for a string — e.g. the last name in a path name.
  • wrap-header-margin size — (integer, default 6) when set (non-negative), the customized header fields specified in header-lines will be split across several lines if they don't fit on one line. When size is greater than zero, lines will be split at the first space occurring in the last size columns of the line. If not set (or negative), long header lines will be truncated if they don't fit on a single line.

🎀 CUSTOMIZED ARTICLE HEADER PRESENTATION 🎀

Normally, nn just prints a (high-lighted) single line header containing the author, subject, and date (optional) of the article when it's read. Cute, but basic.

By setting the header-lines variable as described below, you can get a way more informative multi line header with optional high-lighting and underlining. It's giving glow-up 💅✨.

The header-lines variable is set to a list of header line identifiers, and the customized headers will then contain exactly these header lines in the specified order.

The same specifications are also used by the :print and save-short commands via the print-header-lines and save-header-lines variables.

The following header line identifiers are recognized in the header-lines, print-header-lines, and save-header-lines variables:

  • A — Approved:
  • a — Spool-File: (path of spool file containing the article)
  • B — Distribution:
  • C — Control:
  • D — Date:
  • d — Date-Received:
  • F — From:
  • f — Sender:
  • G — Newsgroup: (current group)
  • g — Newsgroup: (current group if cross-posted or merged)
  • I — Message-Id:
  • K — Keywords:
  • L — Lines:
  • N — Newsgroups:
  • n — Newsgroups: (but only if cross posted)
  • O — Organization:
  • P — Path:
  • R — Reply-To:
  • S — Subject:
  • v — Save-File: (the default save file for this article)
  • W — Followup-To:
  • X — References:
  • x — Back-References:
  • Y — Summary:

The 'G' and 'g' fields will include the local article number if it is known, e.g.

Newsgroup: news.software.nn/754

The following special symbols are recognized in the header-lines variable (and ignored otherwise):

Preceding the identifier with an equal sign "=" or an underscore "_" will cause the header field contents to be high-lighted or underlined. Iconic.

A plus sign "+" will use the shading attribute defined by shading-on and shading-off to high-light the field contents. If no shading attribute is defined it will underline the field instead.

Including an asterisk "*" in the list will produce the standard one line header at that point.

Example: The following setting of the header-lines variable will show the author (underlined), organization, posting date, and subject (high-lighted) when articles are read:

set header-lines _FOD=S

✨ COMMAND LINE OPTIONS ✨

Okay so bestie, some of these options already came up earlier, but here's the full, complete, no-gaps rundown of what every single one does — and we're showing it as the equivalent set, unset, or toggle command, so you can literally see the vibes. 💅

Besides the options below, you can set any of nn's variables directly on the command line with an argument that looks like this:

variable=value

To set or unset a boolean variable, you can give the value as on or off (t and f will also work, cute of them). 🫶

Now, important lore: the init files get read before the options are parsed (unless you use the -I option). So the options that are related to boolean variables set in the init file are gonna toggle whatever value is set there, not the default value. Which means, yeah — the meaning of the options is also user-defined. Very demure, very slay. ✨

The explanations below describe the effect related to the default setting of the variables, with the reverse effect chillin' in square brackets for you. 🎀


  • -aN (set limit N) — Cap the max number of articles shown in each group at N. This is the move when you haven't read news in a hot minute and just want to get up-to-date fast. 🔥
  • -a0 — Mark all unread articles as read. Full explanation lives at the beginning of this manual, go peek. 👑
  • -B (toggle backup) — Do not [do] back up the rc file.
  • -d (toggle split) — Do not [do] split digests into separate articles.
  • -f (toggle fsort) — Do not [do] sort folders according to the subject (instead it presents articles in a folder in the sequence in which they were saved).
  • -g — Prompt for the name of a news group or folder to be entered. 🦋
  • -i (toggle case-fold-search) — Normally searches with -n and -s are case independent. Flip this on and the case becomes significant, so it starts mattering. 🎯
  • -I — Do not read the init file. And bestie, this must be the first option!! The global setup file is still read, though. 🌸
  • -Ifile-list — Specifies an alternate list of init files to load instead of the standard global and private init files. The list is a comma-separated list of file names. Names that don't contain a / are looked for in the ~/.nn directory. An empty element in the list is interpreted as the global init file. This list must not be separated from the -I option by blanks, and it must be the first option. Example: the default behaviour corresponds to using -I,init (first the global file, then the file ~/.nn/init). The global setup file is still read as the first init file independently of the -I option used.
  • -k (toggle kill) — Do not [do] perform automatic kill and selection of articles.
  • -lN (set stop N) — Stop after printing the first N lines of each article. Total lifesaver on slow terminals. 🐢
  • -L[f] (set layout f) — Select alternative menu layout f (ranges from 0 to 4). If f is omitted, menu layout 3 is selected.
  • -m (no corresponding variable) — Merge all articles into one meta group instead of showing them one group at a time. Heads up: when -m is used, no articles will be marked as read. 🙈
  • -nWORD — Collect only articles which contain the string WORD in the sender's name (case is ignored). If WORD starts with a slash /, the rest of the argument is used as a regular expression instead of a fixed string. 🧚
  • -N (no corresponding variable) — Disable updating of the rc file. This includes not recording that groups have been read or unsubscribed to (although nn will think so until you quit). 💀
  • -q (toggle sort) — Do not [do] sort the articles (q means quick, but it isn't any quicker in practice!). 😭
  • -Q (toggle silent) — Quiet mode — don't [do] print the logo or "No News" messages.
  • -r (toggle repeat-group-query) — Make -g repeat the query for a group to enter.
  • -sWORD — Collect only articles which contain the string WORD in their subject (case is ignored). If WORD starts with a slash /, the rest of the argument is used as a regular expression instead of a fixed string. ⭐
  • -S (toggle repeat) — Do not [do] eliminate duplicated subject lines on menus.
  • -T (toggle time) — Do not [do] show the current time in the prompt line. ⏰
  • -w[N] (set window N) — Reserve N lines of the menu screen for a preview window. If N is omitted, the preview window is set to 5 lines. 🎀
  • -W (toggle confirm-messages) — [Don't] wait for confirmation on all messages.
  • -x[N] (set old N) — Present (or scan) all (or the last N) unread as well as read articles. It will never mark unread articles as read, promise. 👑
  • -X (no corresponding variable) — Read/scan unsubscribed groups also. Most useful when you're hunting for a specific subject across all groups, like:
nn -mxX -sSubject all

✨ MACRO DEFINITIONS ✨

okay bestie, so listen: practically any combo of commands and key strokes can be defined as a macro, and then you can bind that whole thing to a single key in menu mode and/or reading mode. It's giving "automation queen" energy. 👑

The macro definition has to specify a sequence of commands and key strokes exactly as if they were typed directly from the keyboard. For example, a string specifying a file name must follow a save command. This manual does not give a complete spec of all the input required by the various commands — it's recommended to execute the desired command sequence from the keyboard prior to defining the macro, so you get the exact requirements of each command. Lowkey important, fr fr.

Although it's possible to define temporary macros interactively using the :define command, macro definitions are normally placed in the init file. Macros are numbered from 0 to 100, i.e. it's possible to define a total of 101 different macros (implicit macros defined with the map command use internal numbers from 101 to 200). No cap, 101 macros. 💅

To define macro number M, the following construction is used (the line breaks are mandatory — don't skip them, bestie):

define M
     body
end

The body consists of a sequence of tokens separated by white space (blanks or newlines). However, certain tokens continue to the end of the current line. So pay attention to which ones are line-hungry. 👀

The following tokens may occur in the macro body:

💬 Comments

Empty lines and text following a # character (preceded by white space) is ignored. So you can leave little notes for yourself. Cute.

⌨️ Command Names

Any command name listed in the key mapping section can be included in a macro, causing that command to be invoked when the macro is executed. Slay.

🧙 Extended Commands

All the extended commands which can be executed through the command command (normally bound to the : key) can also be executed in a macro. An extended command starts with a colon (:) and continues to the end of the current line. Example:

:show groups total

🎹 Key Strokes

A key stroke (which is normally mapped into a command depending on the current mode) is specified as a key name enclosed in single quotes. Examples (A-key, left arrow key, RETURN key):

'A'  'left'  '^M'

🐚 Shell Commands

External commands can be invoked as part of a macro execution. There are two forms of shell command invocations available depending on whether a command may produce output or require user input, or it is guaranteed to complete without input or output to the terminal. The difference is that in the latter case, nn does not prepare the terminal to be used by another program. When the command completes, the screen is not redrawn automatically; you should use the redraw command to do that. The two forms are:

:!echo this command uses the terminal
:!!echo this command does not > /tmp/file

🧵 Strings

Input to commands prompting for a string, e.g. a file name, can be specified in a macro as a double quoted string. Example (save without prompting for a file name):

save-short "+$G"

❓ Conditionals

Conditionals may occur anywhere in a macro; a conditional is evaluated when the macro is executed, and if the condition is false the rest of the current line is ignored. The following conditionals are available:

  • ?menu — True in menu mode
  • ?show — True in reading mode
  • ?folder — True when looking at a folder
  • ?group — True when looking at a news group
  • ?yes — Query user, true if answer is yes
  • ?no — Query user, true if answer is no

Example (stop macro execution if user rejects to continue):

prompt "continue? " ?no break

In addition to these conditionals, it is possible to test the current value of boolean and integer variables using the following form:

?variable=value

This conditional will be true (1) if the variable is an integer variable whose current value is the one specified, or (2) if the variable is a boolean variable which is either on or off. Examples:

?layout=3 :set layout 1
?monitor=on  break
?sort=off :sort age

🛑 break

Terminate macro execution completely. This includes nested macros. Example (stop if looking at a folder):

?folder break

↩️ return

Terminate execution of current macro. If the current macro is called from another macro, execution of that macro continues immediately. So it's like a "just this one, bestie" exit.

⌨️ input

Query the user for a key stroke or a string, for example a file name. Example (prompt the user for a file name in the usual way):

save-short input

✅ yes

Confirm unconditionally if a command requires confirmation. It is ignored if the command does not require confirmation. Example (confirm creation of new files):

save-short "+$G" yes

❌ no

Terminate execution of current macro if a command requires confirmation; otherwise ignore it. If neither yes nor no is specified when a command requires confirmation, the user must answer the question as usual — if the user confirms the action execution continues normally; otherwise the execution of the current macro is terminated. Example (do not create new files):

save-short "+$L/misc" no

💬 prompt string

Print the string in the prompt line (highlighted). The string must be enclosed in double quotes. Example:

prompt "Enter recipient name"

When the macro terminates, the original prompt shown on entry to the macro will automatically be redrawn. If this is not desirable (e.g. if the macro goes from selection to reading mode), the redrawing of the prompt can be disabled by using a prompt command with an empty string (""). Example:

prompt "Enter reading mode?" # old prompt is saved
?no return # and old prompt is restored
read-skip       # changes the prompt
prompt "" # so forget old prompt

📢 echo string

Display the string in the prompt line for a short period. Example:

?show echo "Cannot be used in reading mode" break

📤 puts string-to-end-of-line

The rest of the line is output directly to the terminal without interpretation. Raw. Unfiltered. Periodt.

🪆 macro M

Invoke macro number M. The maximum macro nesting level is five (also catches macro loops). Don't get too inception-y, bestie.


I use the following macro to quickly save all the selected files in a file whose name is entered as usual. It also works in reading mode (saving just the current article). Here's the exact macro, keep it close:

define 1
     :unset save-report
     save-short input yes
     ?menu '+'
     :set save-report
end

✨ The multikey definition table ✨

This one is for squishing multicharacter key sequences down into single characters. No cap. By default the table already holds the mappings for the four cursor keys, and there's room for 10 user-defined multikeys on top of that. The fourteen multikeys are named: up, down, right, left (the four arrow keys 🍓) and #0 through #9 for the user-defined ones.

Multikey #i (where i is a digit or an arrow key name) gets defined like:

map #i key-sequence

where the sequence is a list of 7-bit character names (scroll down, we get to those) separated by spaces. So like, if your HOME key sends the sequence ESC [ H, you can define multikey #0 to be the home key with:

map #0 ^[ [ H

🌈 The input key mapping table

Everything you type gets mapped through the input mapping table, bestie. Which means you can globally remap one key into literally any other key value. By default, all keys are mapped into themselves (iconic, no notes 💅).

To make an entry mapping input-key into new-key, you run:

map key input-key new-key

So if you want your ESC key to function as interrupt, you'd do:

map key ^[ ^G

🎀 The selection mode key binding table

This table says which command fires when you press a key in selection mode — i.e. when the article menu is showing. The command is:

map menu key command

So to bind the HOME key (defined as multikey #0 above) to the select command:

map menu #0 select

And if you want to remap a key to select a specific article on the menu (which is what the a through z keys do by default, bestie), the command has to be written as article N where N is the entry number on the menu counted from zero — so a=0, b=1, ..., z=25, 0=26, ..., 9=35. Like, to map J to select article j:

map menu J article 9

🦋 The reading mode key binding table

Same energy, different mode. This one says which command fires when you press a key in reading mode — i.e. when the article text is on screen:

map show key command

In addition to the direct mappings described above, these variations of the map command exist 🌸:

💫 User defined keymaps

You can define extra keymaps with:

make map newmap

That creates a brand new keymap which you then initialize with normal map commands, like:

map newmap key command

To actually activate a user-defined keymap, it has to be bound to a prefix key:

map base-map prefix-key prefix newmap

When you use it, the prefix key itself doesn't run a command — instead it makes you enter another key, and then it executes whatever command is bound to that key in the keymap bound to the prefix key. (iykyk 🔥)

So for example, to let the key sequence "^X i" execute macro number 10 in both modes:

make map ctl-x
map ctl-x i macro 10
map both ^X prefix ctl-x

🫶 Mapping keys in both modes

Using the pseudo-keymap both, you can map a key to a command in selection and reading mode at once. For example, to map the home key to macro number 5 in both modes:

map both #0 macro 5

⭐ Aliasing

A key can also be mapped directly to the command that's currently bound to another key. Heads up though: later remapping of the other key will not change the mapping of the "aliased" key. The command is:

map keymap new-key as old-key

💜 Binding macros to keys

A macro you already defined can be bound to a key with:

map keymap key macro macro-number

🧚 Implicit macro definitions

You can also define an implicit macro right there in connection with the map command:

map keymap key (
body...
)

🌟 Keys and character names 🌟

Keys and character names are written with this notation:

  • C — a single printable character represents the key or character itself.
  • ^C — this notation represents a control key or character. DEL is written as ^?.
  • 125, 0175, 0x7D — characters and keys can be specified by their ordinal value in decimal, octal, and hexadecimal notation.
  • up, down, right, left — these names represent the cursor keys.
  • #0 through #9 — these symbols represent the ten user-defined multikeys.

If the variable data-bits is 7, key maps can specify binding of all keys in the range 0x00 to 0x7F, and the 8th bit will be stripped in all keyboard input. If the variable data-bits is 8, the 8th bit is not cleared, and key maps are extended to allow binding of keys in the range 0xA0 to 0xFE (corresponding to the national characters defined by the ISO 8859 character sets). Binding commands to these keys can be done either by using their numeric value, or by directly specifying the 8 bit character in the map command, e.g. 🍓

map menu 0xC8 macro 72
map key e %

To show the current contents of the four tables, these versions of the :map command are available:

  • :map — show the current mode's key bindings.
  • :map menu — show the selection mode key bindings.
  • :map show — show the reading mode key bindings.
  • :map # — show the multikey definition table.
  • :map key — show the input key mapping table.

👑 STANDARD KEY BINDINGS 👑

Here's the full list of every command you can bind to keys — selection mode, reading mode, or both. For each command, the default command key bindings in both modes are shown. If a key is not bound in one of the modes but it can be bound, that part is just empty. If the command cannot be bound in a mode at all, that mode says nix. 🚫

  • advance-article — selection mode: nix; reading mode: a
  • advance-group — selection mode: A; reading mode: A
  • article N — selection mode: a-z0-9; reading mode: nix
  • back-article — selection mode: nix; reading mode: b
  • back-group — selection mode: B; reading mode: B
  • cancel — selection mode: C; reading mode: C
  • command — selection mode: :; reading mode: :
  • compress — selection mode: nix; reading mode: c
  • continue — selection mode: space; reading mode: space
  • continue-no-mark — selection mode: return; reading mode: nix
  • decode — selection mode: (empty); reading mode: (empty)
  • find — selection mode: =; reading mode: /
  • find-next — selection mode: nix; reading mode: .
  • follow — selection mode: F; reading mode: fF
  • full-digest — selection mode: nix; reading mode: H
  • goto-group — selection mode: G; reading mode: G
  • goto-menu — selection mode: nix; reading mode: = Z
  • help — selection mode: ?; reading mode: ?
  • junk-articles — selection mode: J; reading mode: nix
  • kill-select — selection mode: K; reading mode: K
  • layout — selection mode: "; reading mode: nix
  • leave-article — selection mode: nix; reading mode: l
  • leave-next — selection mode: L; reading mode: L
  • line+1 — selection mode: , down; reading mode: return
  • line-1 — selection mode: /; reading mode: nix
  • line=@ — selection mode: nix; reading mode: g
  • macro M — selection mode: (empty); reading mode: (empty)
  • mail — selection mode: M; reading mode: m M
  • message — selection mode: ^P; reading mode: ^P
  • next-article — selection mode: nix; reading mode: n
  • next-group — selection mode: N; reading mode: N
  • next-subject — selection mode: nix; reading mode: k
  • nil — selection mode: (empty); reading mode: (empty)
  • overview — selection mode: Y; reading mode: Y
  • page+1 — selection mode: >; reading mode: nix
  • page+1/2 — selection mode: nix; reading mode: d
  • page-1 — selection mode: <; reading mode: delete backspace
  • page-1/2 — selection mode: nix; reading mode: u
  • page=0 — selection mode: nix; reading mode: h
  • page=1 — selection mode: ^; reading mode: ^
  • page=$ — selection mode: $; reading mode: $
  • patch — selection mode: (empty); reading mode: (empty)
  • post — selection mode: (empty); reading mode: (empty)
  • preview — selection mode: %; reading mode: %
  • previous — selection mode: P; reading mode: p
  • print — selection mode: (empty); reading mode: P
  • quit — selection mode: Q; reading mode: Q
  • read-return — selection mode: Z; reading mode: nix
  • read-skip — selection mode: X; reading mode: X
  • redraw — selection mode: ^L ^R; reading mode: ^L ^R
  • reply — selection mode: R; reading mode: r R
  • rot13 — selection mode: nix; reading mode: D
  • save-full — selection mode: S; reading mode: s S
  • save-short — selection mode: O; reading mode: o O
  • save-header — selection mode: E; reading mode: e E
  • save-body — selection mode: W; reading mode: w W
  • select — selection mode: .; reading mode: nix
  • select-auto — selection mode: +; reading mode: nix
  • select-invert — selection mode: @; reading mode: nix
  • select-range — selection mode: -; reading mode: nix
  • select-subject — selection mode: *; reading mode: *
  • shell — selection mode: !; reading mode: !
  • skip-lines — selection mode: nix; reading mode: tab
  • unselect-all — selection mode: ~; reading mode: nix
  • unshar — selection mode: (empty); reading mode: (empty)
  • unsub — selection mode: U; reading mode: U
  • version — selection mode: V; reading mode: V

See the descriptions of the default bindings for a description of the commands, bestie. And the pseudo command nil is the one you use to unbind a key. 💅

💖 THE INIT FILES 💖

okay bestie, gather round, because the init files are literally how you make nn fit your whole vibe — local conventions, restrictions, and every user's personal taste. periodt.

Normally, nn reads up to three init files on start-up if they exist (and listen, all of them are optional, no stress 💅):

  • $LIB/setup — a system-wide file chillin' in the library directory. This one is always loaded before any other init file (even when the -I option is specified, it cannot be skipped, she said what she said). It cannot contain a group presentation sequence.
  • $LIB/init — another system-wide (global) init file, also living in the library directory. This one may be ignored via the -I option.
  • ~/.nn/init — your private init file, in your .nn directory. It's read after the global init file, so you get to change the default setup. main character energy ✨

The init file is parsed one line at a time. If a line ends with a backslash \, the backslash is ignored, and the following line is appended to the current line. (line continuation?? iconic 🎀)

The init file may contain the following types of commands (and data):


🌸 Comments

Empty lines and lines with a # character as the first non-blank character are ignored. Except — tea time 🫖 — where # has another meaning defined by the command syntax (e.g. multi-keys are named #n), trailing comments on input lines are ignored.

🌸 Variable settings

You can set (or unset) all the variables described earlier to change nn's behaviour permanently. The set and unset commands you can use in the init file have exactly the same format as the :set and :unset commands described earlier (except that the : prefix is omitted).

Variables can also be locked via the lock command — this is typically done in the setup file to enforce local policies. 👑

🌸 Key mappings

You can use all the versions of the map command in the init file.

🌸 Macro Definitions

You can define sequences of commands and key strokes using the define...end construction, which can then be bound to single keys with the map command.

🌸 Load terminal specific files

You can load a terminal specific file using

load file

The character @ in the file will be replaced by the terminal type defined in the TERM environment variable. nn silently ignores the load command if the file does not exist (so you don't have to have a specific init file for terminals which does not require remapping). If the file is not specified by an absolute pathname, it must reside in your ~/.nn directory. Examples:

# load local customizations
load /usr/lib/nninit
# load personal terminal specific customizations
load init.@

🌸 Switch to loading a different init file

You can skip the rest of the current init file and start loading a different init file with the following command:

chain file

If this occurs in the private or global init file, the chained init file may contain a sequence part which will replace the private or global presentation sequence respectively.

🌸 Stop loading current init file

You can skip the rest of the current init file with the following command:

stop

🌸 Give error messages and/or terminate

If an error is detected in the init file, the following commands can be used to print an error message and/or terminate execution:

  • error fatal error message... — print the message and terminate execution.
  • echo warning message... — print the message and continue.
  • exit [ status ] — terminate nn with the specified exit status, or 0 if omitted.

🌸 Change working directory of nn

You can use the cd command to change the working directory whenever you enter nn. Example:

# Use folder directory as working directory inside nn
cd ~/News

🌸 Command groups

The init file can contain groups of commands which are executed under special conditions. The command groups are described in the section on command groups below. (iykyk 😌)

🌸 One or more save-files sections

A save-files section is used to assign default save files to specific groups:

save-files
  group-name (pattern) file-name
  ...
end

The group name (patterns) and save file names are specified in the same way as in the presentation sequence (see below). Example:

save-files
  news*  +news/$L
  comp.sources*  /u/src/$L/
end

🌸 The news group presentation sequence

The last part of the init file may specify the sequence in which you want the news groups to be presented. This part starts with the command sequence and continues to the end of the init file.

Both init files may contain a presentation sequence. In this case, the global sequence is appended to the private sequence. 💖

🌸 COMMAND GROUPS 🌸

Okay bestie, so command groups are an init file exclusive — you will not find them anywhere else, and what they do is let you line up a whole little parade of commands that fires off at specific moments during news reading. It's giving scheduled main character behavior. ✨

Heads up tho: from release 6.4 onwards these are still kinda rudimentary (the original says so, not me 💀) and they're a whole mixture of normal init file syntax and macro syntax, depending on whether a given command group only runs at start-up or gets run over and over during your nn session. Pick your syntax accordingly, babes.

A command group opens with the word on and closes with the word end. The ones below get executed conditionally while the init file is being parsed, if their condition is true — and some of them can bring an optional else part that runs when the condition is false:

on condition
     commands
[ else
     commands ]
end

These conditional command groups are the ones you can drop in your init file to run at start-up:

  • on [ test ] — the commands in the group (init file syntax) run only if that test is true. nn literally spawns a shell to run [ test ], so every single option of the test(1) command is at your disposal. Say you wanna unset the flow-control variable when the tty is a pseudo-tty — iconic, do this:
on [ -n "`tty | grep ttyp`" ]
     unset flow-control
end
  • on !shell command — the group runs if the shell command you gave exits with 0 status (i.e. success). ⚠️ Be careful that your command doesn't spew any output — redirect that stuff to /dev/null, fr. Example: to stop people from reading news when the load is above a specific level, you might put this in the global setup file:
on !load-above 5
     error load is too high, try again later.
end
  • on `shell command` string... — the group runs if the first output line from running that shell command is listed among the string values you specified. On later occurrences of this conditional you can omit the shell command entirely and it'll reuse the output from the last shell command. Obsessed with the efficiency. For example, here's how you'd switch init files so you have a limited sequence for news reading during working hours, evenings, and nights:
on `date +%H` 9 10 11 12 13 14 15 16
     chain init.work
end
on `` 17 18 19 20 21
     chain init.evening
else
     chain init.night
end
  • on `` string... — equivalent to the form right above, except instead of executing a shell command, the output from the previous... and that's literally where the sentence stops in the source 🙈 (not my doing bestie, the sentence just trails off like that).
  • on $variable [ value ] — if you give it no value strings, the group runs when that variable is defined in the environment. Otherwise the group runs only if the variable's value shows up in the value list. Example: if you want nn to look for mail in whatever $MAIL is set to — if it's set — you can use:
on $MAIL
     set mail $(MAIL)
end
  • on slow — the commands in the group (init file syntax) run only if your current terminal output speed is less than or equal to the baud rate set in the slow-speed variable. Perfect for optimizing the UI for slow terminals by setting the right variables:
on slow
     set confirm-entry
     set slow-mode
     set delay-redraw
     unset visible-bell
     set compress
     unset header-lines
     set stop 5
     set window 10
end
  • on fast — same as on slow, except the commands only run when the terminal is running at a speed above the slow-speed value. ✨
  • on term term-type... — runs the commands if one of the term-type names is identical to the value of the TERM environment variable. 🌈
  • on host host-name... — runs the commands if the local host's name shows up in the host-name list.
  • on program program-name... — runs the commands if the current program (nn, nncheck, etc) is in the program-name list.

Now the plot twist 💅 — the following on command groups are actually macros, and they may be executed during nn's normal processing. Because of that, they cannot have an else part. No else for you, bestie.

  • on entry [ group list ] — these commands (macro format!) are executed every time nn enters a news group. If you don't specify a group list, the commands get associated with all groups that don't have their own entry macro specified in the group sequence. If you do give a list, the entry macro gets associated with the groups in that list instead. That group list is written using the meta-notations described in the presentation sequence section. 🦋
    • All : commands at the beginning of the command group are executed before nn collects the articles in the group — so yes, you can set or unset variables like cross-post and auto-read-mode-limit before any articles get collected and before the menu is (or isn't) shown. Sneaky and smart.
    • The non-: commands, and any : commands that follow a command of another type, get executed immediately after the first menu page is presented. And if you want to postpone a : command? Use a double :: as the command prefix. Iconic.
on entry comp.sources* alt.sources
     :set cross-post on   # set before collection
     :local auto-read-mode-limit -1   # set before showing menu
     ::unset cross-post   # set after collection
end
  • on start-up — these : commands (macro format!) are executed on start-up, right before nn enters the first news group. Except ✨ the postponed commands (i.e. the non-: ones) won't run until the first group is shown — so yeah, it works exactly like an entry macro.

✨ GROUP PRESENTATION SEQUENCE ✨

okay so bestie, this is the part where we talk about the order your news groups show up in 👑 fr fr.

News groups are normally presented in the sequence defined in the system-wide init file in nn's library directory. that's the default, the blueprint, the vibe the system hands you.

You can personalize the presentation sequence by specifying an alternative sequence in the private init file. The sequence in the private init file is used before the global presentation sequence, and you only need to describe the deviations from the default presentation sequence — like, you don't gotta rewrite the whole thing, just the deltas 💅.

The presentation sequence must start with the word

sequence

followed by a list of the news group names in the order you want them to be presented. The group names must be separated by white space. The sequence list must be the last part of the init file (the parsing of commands from the init file stops when the word sequence is encountered) — so yeah, once nn sees sequence, it's done reading commands, no cap.

You may use a full group name like comp.unix.questions, or just the name of a main group or subgroup, e.g. comp or comp.unix. However — plot twist — if comp precedes comp.unix.questions in the list, this subgroup will be placed in the normal alphabetic sequence during the collection of all the comp groups. so like, order within the collection still gets alphabetized 🫠.

Groups which are not explicitly mentioned in any of the sequence files will be placed after the mentioned groups, unless !! is used and it has not been disabled (as described below).

Each group name may be followed by a file or folder name (must start with either of / ~ or +) which will specify the default save file for that group (and its subgroups). A single + following the group name is an abbreviation for the last save file name used. For example, the following two sequences are equivalent:

group1 +file group2 +file group3 +file
group1 +file group2 + group3 +

When an article is saved, the default save name will be used as the initial contents of the file name prompt for further editing. It therefore does not need to be be a complete file name (unless you use the quick save mode).

Each group name may also be associated with a so-called entry action. This is basically an (unnamed) macro which is invoked on entry to the group (following the same rules as the on entry command group related to :set and :unset commands). iconic behaviour honestly 🎀.

The entry action begins with a left parenthesis ( and ends with a right parenthesis ) on an otherwise empty line:

comp.sources. +src/$L/ (
     :set cross-post
)

The last entry action can be repeated by specifying an empty set of parenthesis, e.g.

comp.unix. +unix ()

The entry action of a preceding group in the sequence can be associated with the current group(s) by specifying the name of the group in the parentheses instead of the commands, e.g.

comp.unix. +unix (comp.sources.unix)

A macro can also be associated with the entry action by specifying its number in the same way as the group name above, e.g.

rec.music. +music (30)

Notice that it is the current definition of the macro which is associated with the group, so if the macro is later redefined with the :define command, it will not have any effect on the entry action. 💀 yeah, snapshot behaviour, it doesn't retroactively update.

Group names can be specified using the following notations:

  • group.name — Append the group (if it exists) to the presentation sequence list. If also-subgroups is set (default), all subscribed subgroups of the group will be included as well (if there are any). Examples: comp, comp.unix, comp.unix.questions. If the group does not exits (e.g. comp), the subgroups will be included even when also-subgroups is not set, i.e. comp is equivalent to comp..

✨ the notations, bestie ✨

  • group.name. — Append the subgroups of the specified group to the presentation sequence. The group itself (if it exists) is not included. Examples: comp., comp.unix..
  • .group.name — Append the groups whose name ends with the specified name to the sequence. Example: .test.
  • group.name* — Append the group and its subgroups to the presentation sequence list (even when also-subgroups is not set). Example: comp.unix*.

The following meta notation can be used in a sequence file. The group.name can be specified using any of the forms described above:

  • ! groups — Completely ignore the group or groups specified unless they are already in the presentation sequence (i.e. has been explicitly mentioned earlier in the sequence).
  • !:code groups — Ignore a selection of groups based on the given code letter (see below), unless they are already included in the sequence. Notice that these forms only excludes groups from the presentation sequence, i.e. they do not include the remaining groups at this point; that must be done explicitly elsewhere.
  • !:U groups — Ignore unsubscribed groups, i.e. if they are neither new, nor present and subscribed in .newsrc. This is useful to ignore a whole hierarchy except for a few groups which are explicitly mentioned in .newsrc and still see new groups as they are created.
  • !:X groups — Ignore unsubscribed and new groups, i.e. if they are not currently present and subscribed in .newsrc. This is useful to ignore a whole hierarchy except for a few groups which are explicitly mentioned in .newsrc. New groups in the hierarchy are ignored unless NEW occurs earlier in the sequence.
  • !:O groups — Ignore old groups, i.e. unless they are new. This is useful to ignore a whole hierarchy but still see new groups which are created in the hierarchy (it might become interesting some day). Individual groups can still be included in the sequence if they are specified before the !:O entry.
  • !:N groups — Ignore new groups in the hierarchy.
  • !! — Stop building the presentation sequence. This eliminates all groups that are not already in the presentation sequence.
  • NEW — This is a pseudo group name which matches all new groups; you could place this symbol early in your presentation sequence to see new groups out of sequence (to attract your attention to them).
  • RC — This is a pseudo group name which matches all groups occurring in the .newsrc file. It will cause the groups in .newsrc to be appended to the presentation sequence in the sequence in which they are listed in .newsrc.
  • RC:number — Similar to the RC entry, but limited to the first number lines of the .newsrc file. Example: RC:10 (use 10 lines of .newsrc).
  • RC:string — Similar to the RC entry, but limited to the lines up to (and including) the first line (i.e. group) starting with the given string. For example: RC:alt.sources
  • < group.name — Place the group (and its subgroups) at the beginning of the presentation sequence. Notice that each < entry will place the group(s) at the beginning of the current sequence, i.e. < A < B < C will generate the sequence C B A. yes it flips, that's on purpose bestie 🙈.
  • > group.name — Place the group (and its subgroups) after all other groups that are and will be entered into the presentation sequence.
  • @ — Disable the !! command. This can be included in the personal presentation sequence if the global sequence file contains a !! entry (see example 1 below).
  • % .... % — Starts and ends a region of the sequence where it is possible to include groups which has been eliminated earlier. This may be useful to alter the sequence of some groups, e.g. to place comp.sources.bugs after all other source groups, the following sequence can be used:
! comp.sources.bugs comp.sources* % comp.sources.bugs %

🌸 Examples 🌸

Example 1: In a company where ordinary users only should read the local news groups, and ignore the rest (including new news groups which are otherwise always subscribed to initially), can use the following global presentation sequence:

general
follow
! local.test
local
!!

The "expert" users in the company must put the @ command somewhere in their private sequence to avoid losing news groups which they have not explicitly mentioned in their init file.


Example 2: This is the global sequence for systems with heavy news addicts who setup their own sequences anyway.

# all must read the general news first
< general
# test is test, and junk is junk,
# so it is placed at the very end
> test
> .test
> junk
# this is the standard sequence which everybody may
# change to their own liking
local     # our local groups
dk   # the Danish groups
eunet.general # to present it before eunet.followup
eunet     # the other European groups
comp # the serious groups
news # news on news
sci  # other serious groups
rec  # not really that important (don't quote me)
misc # well, it must be somewhere
# the groups that are not listed above goes here

Notice the use of comments in the sequence where they are allowed at the end of non-empty lines as well. 💅


Example 3: My own presentation sequence (in the init file) simply lists my favourite groups and the corresponding default save files:

sequence
  !:U alt*  # ignore unsubscribed alt groups
  news.software.nn +nn
  comp.sys.ti* +ti/$L
  NEW  # show new groups here
  news*
  rec.music.synth +synth/
  comp.emacs*,gnu.emacs +emacs/misc
  comp.risks +risks
  eunet.sources +src/unix/
  comp.sources* +src/$L/

The presentation sequence is not used when nn is called with one or more news group names on the command line; it is thus possible to read ignored groups (on explicit request) without changing the init file. (Of course, you can also use the G command to read ignored groups). 🦋


💫 MERGING NEWS GROUPS 💫

ok so remember the third example up top? it had this line in it:

comp.emacs*,gnu.emacs +emacs/misc

that, bestie, is the merge groups syntax ✨ when two or more groups get merged, all the new articles in those groups show up together like they were one single group. the whole vibe is unity 🫶

to merge groups you list their names together in the sequence, separated only by a single comma. no extra spaces, no drama, just one lil comma.

and if you wanna merge the groups that come out of one group pattern (like comp.emacs*), the pattern has to be followed by a comma and a blank, like this:

comp.emacs*, ...

merged groups get presented as the first group in the "list", and the word MERGED shows up after the group name. iconic behavior honestly 👑

the Y {overview} command will still show merged groups as individual groups, BUT they'll be annotated with a & symbol on the first of the groups, and a + on all the rest. little markers, big meaning 💅

heads up: in the current version, the whole concept of "the current group" when merged groups are involved is a bit fuzzy. the only place you'd really notice is the G command, which takes the most recently used group among the merged groups as the current group. so stuff like G = ... might not always work the way you expect. no cap, it's just a lil quirky 😭

🌿 ENVIRONMENT 🌿

these are the environment variables nn actually uses, bestie:

  • EDITOR — the editor that gets invoked when you're editing replies, follow-ups, and composing mail. nn knows about these editors: vi, ded, GNU emacs, and micro-emacs, and it'll try to put the cursor on the first line following the header — that means after the blank line, which must not be deleted! 🚨 if an article has been included, the cursor lands on the first line of the included text (so you can yeet sections you don't want, easily).
  • LOGNAME — taken as the login name of the current user. nn uses it to return failed mail. if it's not defined, nn will use the value of USER, and if that's not defined either, nn will use the call who am i to get this info. and if all attempts fail? the failed mail gets dropped in the bit bucket. rip 🗑️
  • PAGER — used as the initial value of the pager variable.
  • SHELL — the shell that gets spawned if the system cannot suspend nn, and it's also used to execute the shell escapes.
  • TERM — the terminal type.

📝 NOTES 📝

when NNTP is being used over a slow link (think ppp protocol plus a modem, the struggle 💀), you might wanna suppress the retrieval of info about new newsgroups and their purpose, because that stuff can be hundreds of KBytes in size. to do that, set the new-group-action and show-purpose-mode variables to 0 in your init file. check out those variables' descriptions for the full tea 🍵

unfortunately, the list of active newsgroups is still fetched, because nn uses it to figure out which groups to check for new articles. even that could be avoided, but the cost would be checking for new articles in every group, which might well be slower overall — although startup would be faster. trade-offs, bestie, trade-offs ⚖️


📁 FILES 📁

  • ~/.newsrc — the record of read articles.
  • ~/.nn/select — the record of selected and seen articles.
  • ~/.nn/init — personal configuration and presentation sequence.
  • ~/.nn/kill — the automatic kills and selections.
  • ~/.nn/KILL.COMP — the compiled kill file.
  • ~/.nn/LAST — the time stamp of the last new news group we have seen.
  • ~/.nn/NEXTG — active group last time nn was quit.
  • ~/.nn/.param — parameter file for the aux script.
  • $lib/setup — system-wide setup; always read first.
  • $lib/init — system-wide setup and presentation sequence.
  • $lib/aux — the response edit and send script.
  • $lib/routes — mapping rules for mail addresses (on non-domain systems).
  • $db/* — the news data base.
  • /etc/termcap — terminal data base [BSD].
  • /usr/lib/terminfo/* — terminal data base [SysV].
  • /usr/local/lib/nntp_server — name of remote nntp server, if not changed by setting the environment variable NNTPSERVER or the nntp-server variable on the command line.

and the names $lib and $db are the directories used for the auxiliary files and the news data base respectively. their name and location is defined at compile time. common choices are /usr/local/lib/nn or /usr/lib/news/nn for $lib, and /usr/spool/nn or /usr/spool/news/.nn for $db. iykyk 🌈


👀 SEE ALSO 👀


👑 ORIGINAL AUTHOR 👑

Kim F. Storm, Texas Instruments A/S, Denmark


🫶 CURRENT MAINTAINER 🫶

Michael T Pins mtpins@nndev.org

the NNTP support was designed and implemented by Rene Seindal, Institute of Datalogy, University of Copenhagen, Denmark.

the news.software.nn group is used for discussion on all subjects related to the nn news reader. this includes, but is not limited to, questions, answers, ideas, hints, information from the development group, patches, etc.


and that's a wrap on the whole page, bestie!! 🎀 this was the 4th Berkeley Distribution, Release 6.7.5, dated on the NN(1) manual page — go forth and news-read like the main character you are 💖✨

📦 where this page comes from
  • ubuntu stonking: nn 6.7.5-1 · permissive
  • 💖 girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms