Skip to content
Ilia Maslakov edited this page Sep 24, 2026 · 1 revision

Help markup

The help the program shows with F1 and the man pages come from the same markdown. go-md2man turns it into roff, src/help_md.c turns it into what the help window paints. A page has to read right in both, and the rules below are what the two renderers do, not a matter of taste.

Which file a chapter belongs to

The help is split by program, one file each:

file what it holds
doc/man/mcommander.md the file manager, and what the whole suite shares
doc/man/mview.md the viewer
doc/man/mcedit6.md the editor
doc/man/mdiff.md the compare view
doc/man/mctree.md, doc/man/mcstruct.md man pages of those two names
doc/hlp/xnc.md screens that exist only in the help, with no man page
doc/man/<lang>/*.md, doc/hlp/<lang>/xnc.md the same set per language

A plugin keeps its help beside itself, src/panel-plugins/<name>/<name>_panel.md, and never in the core files. The core knows no list of these files: a dialog names its own file through WDialog.help_file, quick_dialog_t.help_file or ev_help_t.filename, with the constant declared in the header of that program (MCVIEW_HELP_FILE, MCEDIT_HELP_FILE, MCDIFF_HELP_FILE).

Nodes and anchors

A dialog asks for its node by name:

quick_dialog_t qdlg = {
    .title = _ ("Viewer options"),
    .help = "[Viewer options]",
    .help_file = MCVIEW_HELP_FILE,
    ...
};

help_md_node_id() folds that name to a slug: lower case, a run of spaces or dashes becomes one dash, everything but letters, digits and _ is dropped. A heading is known by the slug of its title, or by an explicit anchor:

# Viewer options

gives the node viewer-options. A translation keeps that same node by naming it:

# Настройки просмотра <a id="viewer-options"></a>

A node no file has gives the message box Cannot find node [Viewer options] in help file and the help falls back to the first page, so a new dialog and its node belong in the same commit.

Three markers steer the help:

# NAME <!-- help:skip -->
# Key Bindings <!-- help:notitle --><a id="key-bindings"></a>
<!-- help:topics "Topics:" -->

help:skip leaves the section out of the help and keeps it in the man page, help:notitle prints the body without the heading, and help:topics gives the contents page its heading, once per file at the top.

A list of keys, options or files is a definition list

This is the shape every OPTIONS and key section uses, and the one to reach for by default:

*-d, --nomouse*
: Disable mouse support.

**F5**
: Goto. The dialog takes a line number, a percentage of the size of the file,
or an offset written in decimal or in hexadecimal, whichever of the four is
chosen in it.

The term stands on its own line, the body starts with : , and the lines that continue the body start at column 0. Markup works inside: **bold** for keys, *italic* for options, variables and file names. Both renderers indent the body and keep the term apart.

A block only for what is really preformatted

Enter        expand/collapse the current node; on a leaf show
             the full value
Right/Left   expand / collapse (on a collapsed node Left jumps
             to the parent)
*            expand the current subtree recursively

A fenced block keeps its lines as they stand in both renderers. Use it for columns that have to line up, for examples, for ini snippets and for ASCII art. Two limits: markup does not work inside, so **bold** prints as it stands, and the help window has 62 columns for text, so keep a line at 60 characters or less or it wraps and the columns break.

Wrong, because a definition list carries it better:

F5    Add extra shortcut
F8    Remove shortcut

Right:

**F5**
: Add extra shortcut.

**F8**
: Remove shortcut.

What breaks the help window

  • Two spaces at the end of a line are the hard break of markdown. They work in both renderers, but they are invisible in the source and editors strip them: use a block or a definition list instead.
  • A continuation line that starts with a space. The help window keeps that space in the middle of the paragraph, and roff turns the line into a break with an indent. Continuation lines start at column 0.
  • A quote under a one line paragraph. go-md2man turns that one line paragraph into a section heading:
Search of keymap-file will occur in:

> 1) ~/.config/mc6/

maint/check-man.pl reports it. Give the paragraph a second line, or drop the quote for a block.

  • A GFM table and a backslash inside a link label: the same checker catches both.

Links

[Listing Format...](#listing-format)
[Edit Extension File](mcommander.md#edit-extension-file)
<https://github.com/blue-panels/mcommander/issues>

A link to a node prints as its text in the man page; in the help the second form opens that file at that node, which is how the chapters of the programs reach each other.

After every edit

$ sh maint/update-man-in.sh .
$ perl maint/check-man.pl .
27 files checked, 0 errors, 0 warnings

Everything under doc/man/*/roff/ is generated from the markdown and is never edited by hand; CI regenerates it and compares. The help files themselves are built by make into <build>/doc/hlp/.

Seeing the result before installing

$ make -j8
$ mkdir /tmp/help && cp <build>/doc/hlp/*.md <build>/doc/hlp/*/*.md /tmp/help/
$ LD_LIBRARY_PATH=<build>/lib/.libs unshare -Urm bash -c \
    'mount --bind /tmp/help /usr/share/mcommander/help;
     exec -a mview <build>/src/.libs/mcommander FILE'

Two traps. <build>/src/mcommander is a libtool shell wrapper that replaces argv[0], so the dispatch by program name needs src/.libs/mcommander. Without LD_LIBRARY_PATH the binary loads the installed libmc, and a change under lib/ does not show. Driving it in a pty: mc turns on application cursor keys, so the arrows are \x1bOA .. \x1bOD, and F9 opens the menu bar while Enter drops it.

Clone this wiki locally