screenshot ───────────────── #Sed-based MarkDown viewer and linter ────────────────── This document is meant to be rendered using smd. If not, some renderings won't work as intended. You can see the document as intended by copy-pasting the following in a terminal: ┌── shell ─── │ url='https://codeberg.org/johann1764/smd/raw/branch/main/smd' │ smd="$(mktemp -d --tmpdir)" │ wget -P "$smd" "$url.sh" "$url.md" │ chmod +x "$smd/smd.sh" │ "$smd/smd.sh" -d ╵ or by visiting the HTML-ified term outputs: • dark theme • light theme ▄ █#Overview ▀────────── smd is a tool for viewing markdown files in a terminal that is feature-rich yet easy to use: ┌── shell ─── │ smd Readme.md ╵ will generate a view of Readme.md and output the result to less, allowing the user to navigate it. The set of markdown extensions vary from one implementation to another. smd offers the ability to process md files in order to make them understandable by most implementations, and to look good even when read as a pure text. ┌── shell ─── │ smd -i Readme.md ╵ will process Readme.md. Several options are available. As an example smd -r -f -i smd.md was used to process this file, and therefore this will have no effect if applied once more. This tool only requires bash and GNU sed, which are included with any GNU/Linux distribution. If you want to benefit from syntax highlighting, you also need bat. No build step is required: it works as is. smd is focused on: 1. providing a beautiful and readable view of md files; and 2. providing a lint process that helps to produce a md file that is both portable and is easy to read as text-only. Providing a pager or other terminal interactive utilities is out of scope of smd. smd mostly follows and extends commonmark specification, with a few exceptions: • smd refuses to embed section titles into lists. • smd makes a difference between thematic breaks declared with dashes and thematic breaks declared with stars. • smd makes a difference between blocks that are separated with a blank line and blocks which are not: a fenced code block may either interrupt an existing paragraph or start a new one. ▄ █#1 ─#Install and a Note on Performance ▀─────────────────────────────────────── From a repository clone, installation is fairly trivial: ┌── shell ─── │ sudo cp smd.sh smd.md /usr/share && │ sudo ln -s /usr/share/smd.sh /bin/smd ╵ Updating with a new version is done with the first line, and uninstalling is obvious: ┌── shell ─── │ sudo rm -fv /usr/share/smd.sh /usr/share/smd.md /bin/smd ╵ You can also install/update smd from scratch by copy-pasting the following in a terminal emulator: ┌── shell ─── │ url='https://codeberg.org/johann1764/smd/raw/branch/main/smd' │ sudo wget -N -P /usr/share/ "$url.sh" "$url.md" && │ sudo chmod +x /usr/share/smd.sh && │ sudo ln -s /usr/share/smd.sh /bin/smd ╵ and then running: ┌── shell ─── │ smd -d ╵ will get you back to that documentation. You can try with an additional -2 to display it with two columns. See screenshots with two columns (light theme) and section Command Line Usage. If need be, you can activate --redraw-on-quit in less to keep the last output page of smd on the terminal. On performance: • on a Raspberry pi 4, smd has a small latency at startup. It will be mitigated, as there is room for speed improvement. • smd streams its output: as a consequence, opening a 1000-pages document will take exactly as much time as opening a 2-pages document. However, pressing END will force the processing of the whole file, which might take some time when reading a huge document on a slow machine. This processing occurs even if you don't scroll, so it will usually long be over by the time you finish reading the first page. ▄ █#2 ─#Features ▀────────────── Not all features will be detailed here, only the ones that: • need documentation, such as syntax highlighting. • make this program unique, most noticeably: text justification, vertical space management, OSC8 links, and overall attention to details. (Also, there is a two columns mode, see Command Line Usage.) In the rest of this document, unique features are marked with a star *. █#2.1 ─#Text Justification* and Paragraph Breaks smd justifies its paragraph in view mode, just like man does for the man pages. For portability reasons, in linter mode, it just breaks lines without space-padding them. This feature looks obvious, but surprisingly enough, no markdown reader I know of does that. The line length is fixed to slightly more than the optimal readability length. When the output is a terminal, the line length is decreased if needed to fit the terminal width. The default maximum screen width can be modified with the environment variable SMD_W. Par breaks allows to break line inside a paragraph. This can be done with two trailing spaces, a <br/>, //, or \. All these sequences except the backslash \ may be followed by spaces. For example: ┌── md ─── │ This is a line that needs a break at some point because it is a bit │ long. This is a line │ that does not need it. │ │ This is the first line\ │ This is the second one<br/> │ This is the third one with 2 trailing blanks██ │ and just adding a newline is not │ enough. │ │ This is a line with a `<br/>` <br/> in the middle. ╵ results in: ╷ │ This is a line that needs a break at some point because it is a bit │ long. This is a line that does not need it. │ │ This is the first line │ This is the second one │ This is the third one with 2 trailing blanks │ and just adding a newline is not enough. │ │ This is a line with a <br/> │ in the middle. ╵ I follow commonmark suggestions on this topic, therefore linter mode expresses all par breaks using <br/>: ┌── md ─── │ This is a line that needs a break at some point because it is a bit long. │ This is a line that does not need it. │ │ This is the first line<br/> │ This is the second one<br/> │ This is the third one with 2 trailing blanks<br/> │ and just adding a newline is not enough. │ │ This is a line with a `<br/>`<br/> │ in the middle. ╵ Note: when no space is available for cutting the line the line is just not cut. This allow to detect problems more easily (like too long in-text quotes), and also preserves the links destination in lint mode, therefore keeping them clickable on your terminal emulator. █#2.2 ─#Sections ▒#2.1 ─#Sections and Vertical Space* (Sub)sections are surrounded by vertical space, whose amount depends on their hierarchical level, just like in LaΤeχ. They consume any additional blank line. When two (sub)sections follow each other, the space in between depends on the second one, therefore the first one after space is ignored in this case. In the case the first one is a subsection and the second is a subsubsection, the contrary happens. Why? Because it looks better this way. OK, but why? Visually, the dash-underlining of the subsection name works as a blank line, so it has to be compensated for. That is why. Besides this, the blank lines may or may not occur anywhere. However, multiple blank lines have the same effect as a single one. If the file begins (resp. ends) with blank lines, one of them is kept. (Sub)sections preceded by the beginning of the file have no preceding space. ▒#2.2 ─#Section Layout (with italics) smd provides different spacing and rendering for all five hierarchical levels. I recommend reserving level 1 for titles, or parts in a document that require a deep structure. As a rule of thumb, here are the levels of hierarchy you want to use in priority: 3, 2 and/or 4, 1, 5. If you have a document with low-level sections and want to improve the layout without changing their level, the -s option allows to have the layout and spacing of section n+1 at level n. Section titles may contain bold and italics. If this is redundant with the section layout, the meaning of these are reversed*: if a section is naturally bold, its bold content will be the only content that won't be bold in the output, and similarly for italics. In a faint context, faint characters will stay as is. For the sake of the demonstration, this document uses an exaggerated sectioning depth, and the level 5 is shown below, which allows to see how it looks. In a general setting, it is advisable to use less than that (2 or 3 in most cases). ░#A fake depth-5 section title with a link inside This is test text: The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. ░#Another fake section title with bold and italics words This is test text again. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. Again. ▒#2.3 ─#Automatic Section Numbering* smd can perform automatic section numbering, which is an extension of the markdown syntax. When a section name begins with <n> ?- or with <n>(.<n>)+, it is considered a section number. For example: ┌── md ─── │ ## 1 - section │ ### 1.1 subsection ╵ are valid numbered sections. By contrast: • # 1789 is not; • # 39 -- 45 is not (see Em dash, En dash and Dots) • ## 1. section is not, because we would also have to accept: ┌── md ─── │ 1. section │ ---------- ╵ which is ambiguous, and therefore non-portable. The last number refers to the current sectioning depth, and the number of dots is used as a formatting hint. For example, current section is defined as: ┌── md ─── │ #### 1.1.1 Automatic Section Numbering\* ╵ Therefore, the level 4 counter is increased, and the expression <lev2>.<lev3>.<lev4> is used to generate the section name. Unnumbered sections do not affect the counters, but appear in the table of contents. Notice that, in view mode, there is an invisible # before both the section number and the section name. This allows to look for a section using either its number or its name. A quick way to add numbers to an existing document, say Readme.md: ┌── bash ─── │ smd -a -i Readme.md │ sed 's/^#\(#\+\) /#\1 \1 /;ta;b;:a;s/^\(#\+ \(1\.\)*\)#/\11./;ta' -i Readme.md │ sed 's/^\(#* \(1\.\)*1\)\./\1/;s/^## 1/&-/' -i Readme.md │ smd -i Readme.md ╵ The -a option of the first line allows to turn section alternate form into the primary #-form. Notice you may use all your favourite options (-f, -s, etc.) on the last line. If you want some sections to be unnumbered, just remove their numbers and re-apply smd. ▒#2.4 ─#Alternate Section Form Parsing A line followed by three or more = (resp. -) is a section 1 (resp. 2) title. Markdown is ambiguous about what happens when you have: ┌── md ─── │ line1 │ line2 │ --- ╵ With smd, this is considered equivalent as: ┌── md ─── │ line1 │ ## line2 ╵ while commonmark considers it equivalent as: ┌── md ─── │ ## line1 line2 ╵ which makes it easier to do multi-line titles. From my perspective, making easier to do inadvisable things is a bad design choice. The reader currently used does: ╷ │ line1 │ │ │ │ ▄ │ █line2 │ ▀────── │ ╵ In its output, the linter uses the alternate form, which allows a clearer sectioning structure. Sometimes it is easier to work with the base form. This can be achieved with option -a or --no-alt. █#2.3 ─#Syntax Highlighting and Code Details Reminder: the code may either be: • a 4-indented block, called indent code or • a code delimited by at least three ` or at least three ~, called fenced code block. ▒#2.1 ─#Syntax Highlighting smd relies on bat for syntax highlighting. If it is not installed, the code will stay gray, like indent code or anonymous fenced code. This can be installed with: ┌── shell ─── │ sudo apt-get install bat ╵ For syntax highlighting to work, the markdown file must use the same names for languages as bat does. In order to get the long list of bat recognized languages: ┌── shell ─── │ batcat -L ╵ As a convenience, we provide aliases through the SMD_LANG_ALIASES environment variable. By default, it only contains "shell:bash", meaning code in shell code environment (like in the previous one) will be formatted by bat as if it were bash. Several aliases can be separated by , or spaces. ▒#2.2 ─#Code Details* The fenced code indentation is relative to the least indented line, including the opening fence: ┌── md ─── │ 1. case 1: │ ``` │ line │ ``` │ 1. case 2: │ ``` │ line │ ``` │ 1. case 3: │ ``` │ line1 │ line2 │ ``` ╵ Let's try: ╷ │ 1. case 1: │ ┌── │ │ line │ ╵ │ 2. case 2: │ ┌── │ │ line │ ╵ │ 3. case 3: │ ┌── │ │ line1 │ │ line2 │ ╵ ╵ Fenced code environment preserve up to one leading and trailing blank lines. As an extension, smd accepts closing sequence at the end of the last line of code. Furthermore, the closing sequence allows the paragraph to continue without a newline: ┌── md ─── │ Some paragraph │ ``` │ do it``` continues here ╵ gets linted into: ┌── md ─── │ Some paragraph │ ``` │ do it │ ``` │ continues here. ╵ Test: ╷ │ Some paragraph │ ┌── │ │ do it │ ╵ │ continues here ╵ Finally, code lines are not wrapped. This is a design choice; the motivation behind is that code should be taken literally, and not interpreted in any way. For the same reason, inline code `inline code` is not wrapped either. But since inline code is not supposed to contain newlines, when it does, it gets linted into inline code where the newline and its surrounding spaces are replaced by a single space: ┌── md ─── │ A ``recursive `inline │ code` `` example. ╵ results in: ╷ │ A recursive `inline code` example. ╵ Notice however that: ┌── md ─── │ `inline <br/> │ code` ╵ gives: ╷ │ `inline │ code` ╵ This is because the sub-paragraph splitting has a higher priority than the quote protection. Here, there is no inline code, just separate unprotected backquotes on separate lines. █#2.4 ─#Indentation and Lists ▒#2.1 ─#Indentation and List Nesting We follow commonmark (weird but understandable) specifications: ┌── md ─── │ First situation: │ - first │ - second │ - third │ │ Second situation: │ - first │ - third │ - second ╵ should be correctly understood as: ┌── md ─── │ First situation: │ * first │ * second │ * third │ │ Second situation: │ * first │ - third │ * second ╵ Test: ╷ │ First situation: │ • first │ • second │ • third │ │ Second situation: │ • first │ ‒ third │ • second ╵ Unlike some other md readers, here all environments (including other lists) can be nested into list items or sub-items, inheriting their indentation: ┌── md ─── │ ``` │ root-level code │ ``` │ * item │ ``` │ item level code │ ``` ╵ results in: ╷ │ ┌── │ │ root-level code │ ╵ │ • item │ ┌── md ─── │ │ item level code │ ╵ ╵ Note that, contrary to the commonmark specification, (sub)sections are not embeddable in lists: it would not make sense. ▒#2.2 ─#List Numbering and Layout Currently, list item layout only depend on nesting depth, and therefore *, -, and + will have the same effect. Therefore: ┌── md ─── │ 1. a numbered item .... .... .... .... .... .... .... .... │ .... .... .... .... .... .... │ 1. a numbered sub-item │ 1. a numbered sub-item │ 1) a numbered sub-item (alternative form) │ * an unnumbered item .... .... .... .... .... .... .... .... │ .... .... .... .... .... .... │ + another unnumbered item │ - [x] a checkbox .... .... .... .... .... .... .... .... .... │ .... .... .... .... .... .... .... .... .... │ 1. another numbered item │ - [x] at level 2 .... .... .... .... .... .... .... .... │ .... .... .... .... .... .... │ - at level 3 .... .... .... .... .... .... .... .... │ .... .... .... .... .... .... │ 1. at level 3 .... .... .... .... .... .... .... .... │ .... .... .... .... .... .... │ - [x] at level 3 .... .... .... .... .... .... .... │ .... .... .... .... .... .... │ - at level 4 .... .... .... .... .... .... .... │ .... .... .... .... .... .... .... ╵ gives: 1. a numbered item .... .... .... .... .... .... .... .... .... .... .... .... .... .... 1. a numbered sub-item 2. a numbered sub-item 3. a numbered sub-item (alternative form) • an unnumbered item .... .... .... .... .... .... .... .... .... .... .... .... .... .... • another unnumbered item [✓] a checkbox .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... 2. another numbered item [✓] at level 2 .... .... .... .... .... .... .... .... .... .... .... .... .... .... • at level 3 .... .... .... .... .... .... .... .... .... .... .... .... .... .... 1. at level 3 .... .... .... .... .... .... .... .... .... .... .... .... .... .... [✓] at level 3 .... .... .... .... .... .... .... .... .... .... .... .... .... ‒ at level 4 .... .... .... .... .... .... .... .... .... .... .... .... .... .... █#2.5 ─#Hyperlinks, References and Inclusion ▒#2.1 ─#OSC8 Links* Using OSC8, we can have: ┌── md ─── │ - [http link](https://codeberg.org/johann1764/smd/) │ - [local file](Readme.md) │ - [in-document link](#2-5-2-references) ╵ rendered into: • http link • local file • in-document link On a terminal emulator, this results in a clickable link while only the link text is displayed. The first two appear to work on different terminal emulators. However, a terminal emulator does not know what to do with the last one. First of all, we can use the pattern matching of less (use /). In viewer mode, all (sub)sections numbers and names are preceded by an invisible #, therefore looking for #2.5 and #Hyperlinks will both match the title above. As a nice side-effect, just typing /#<RET> a first time in less and then re-typing /<RET> repeatedly allows to scroll through sections. In addition of that, we can look for the local link label. The section labeling convention seems to consists in applying the following to the section title (including its numbering) • lower the case of every letter, • replace any non-alphanumeric sequence of characters is by -, • remove any potential leading or trailing -, and • add a leading #. Therefore, a link to this section will have label: #2-5-hyperlinks-references-and-inclusion, e.g. link to this section. Your terminal gives you the label when you let your cursor on it. This label can also be looked for, as, in viewer mode, each section is preceded by a seemingly blank line that in fact contains this label, but concealed. It can be copy-pasted. Some additional ideas to manage references to sections are proposed in the Future Improvements section. Notice that hyperlinks can be split by newlines in viewer mode without any problem: the two resulting chunks will be valid hyperlinks. Someone nicely maintains a list of terminals that accept OSC8 here. If your terminal does not display the OSC8 links (that materializes with a dotted underlining of the link and a context box suggesting to follow the link) then please send me the result of ┌── bash ─── │ echo "\"$TERM\"" ╵ called from your terminal. I will add this terminal name to the list of terminals needing explicit links, like it is already done for the tty. ▒#2.2 ─#References ┌── md ─── │ This is a [reference][ref]. │ This is a footnote[^1]. ╵ gives: This is a reference[ref]. This is a footnote[^1]. Such a reference can be defined before or after with: ┌── md ─── │ [ref]: https://en.wikipedia.org/wiki/Hyperlink │ [^1]: Yes, absolutely. ╵ Look at the result! The choice were made not to use OSC8 for the reference: this allows to have explicit links in the document in a way that does not hinder reading, and the final link stays clickable. As before, going to reference definition is easy by searching its expression with the square brackets. By default, the references are deferred to right before the beginning of next section of level 3. Using the environment variable SMD_FLUSH_FOOT, it is possible to configure this behavior*. Setting it to n means: "defer it to before the beginning of the next section of level n or less". In particular, 5 means any section (as this is the max level of a section), and 0 means the end of the document. If it is set to anything other than a number, references and footnotes are left where they are. ▒#2.3 ─#Coming Soon: Inclusion* This has not been implemented yet. For including files, we extend the link syntax by introducing an additional () part. This allows the other markdown readers, that don't understand that extension, to render it as a simple link, followed by a few weird things in parentheses. This additional () allows to specify the kind of inclusion: direct (with optional -o parameters, see --hierarchy-offset), code (with optional language specification), or quote. ┌── md ─── │ [direct inclusion](file.md)() │ [direct inclusion with -o '2!'](file.md)(2!) │ [code inclusion](file.md)(.) │ [code inclusion (lang=md)](file.md)(.md) │ [quote inclusion](file.md)(>) ╵ This has not been implemented yet. They all accept an optional [<n1>-<n2>], with both <n1> and <n2> optional, at the end of the () part, that allows to get only a subset of the lines, like that: ┌── md ─── │ [code inclusion](file.md)(.md[15-20]) ╵ resulting in: ╷ │ code inclusion(.md[15-20]) ╵ Notice that if you create loops of direct or quote inclusions, i.e. [](file2.md)() in file1.md and [](file1.md)() in file2.md, then it will cause an infinite loop. Avoiding circular inclusions is your responsibility. The simplest way to do that is to organize your files in directories, with the rule that a file should only include files that are in sub-directories relative to it. Notice that the included files lose their streaming ability: the whole included file has to be processed before it is added to the output stream. ───────────────────────── [ref]: https://en.wikipedia.org/wiki/Hyperlink [^1]: Yes, absolutely. █#2.6 ─#Arrays The arrays are fully conforming to commonmark specifications like, for example, glow does. This example is adapted from one of theirs: ┌── md ─── │ | Name | Power | Comment | │ | ---: | :---: | :--- | │ | Carrots | 9001 | It’s over 9000?! | │ | Ramen | 9002 | Also over 9000?! | │ | Currywurst | **100000** | What?! | ╵ gets linted into: ┌── md ─── │ | Name | Power | Comment | │ | ---------: | :--------: | ---------------- | │ | Carrots | 9001 | It’s over 9000?! | │ | Ramen | 9002 | Also over 9000?! | │ | Currywurst | **100000** | What?! | ╵ and rendered into: ┌────────────┬────────┬──────────────────┐ │ Name │ Power │ Comment │ ├────────────┼────────┼──────────────────┤ │ Carrots │ 9001 │ It’s over 9000?! │ │ Ramen │ 9002 │ Also over 9000?! │ │ Currywurst │ 100000 │ What?! │ └────────────┴────────┴──────────────────┘ Arrays can contain bold, italics, bold italics, andstricken outparts, and they can also contain links (see above). █#2.7 ─#Quotes & Admonitions ▒#2.1 ─#Quotes They work! They get uncolored, though, in order to avoid visual chaos. However, links are preserved. ╷ │ They work! They get uncolored, though, in order to avoid visual │ chaos. However, links are preserved. │ │ │ They work! They get uncolored, though, in order to avoid visual │ │ chaos. However, links are preserved. ╵ Quotes preserve up to one leading and trailing blank lines. ▒#2.2 ─#Admonitions ┌── md ─── │ > [!NOTE] │ > General information or additional context. │ │ > [!TIP] │ > A helpful suggestion or best practice. │ │ > [!IMPORTANT] │ > Key information that shouldn't be missed. │ │ > [!WARNING] │ > Critical information that highlights a potential risk. │ │ > [!CAUTION] │ > Information about potential issues that require caution. ╵ generates: ╷ │ [Note] │ General information or additional context. ╵ ╷ │ [Tip] │ A helpful suggestion or best practice. ╵ ╷ │ [Important] │ Key information that shouldn't be missed. ╵ ╷ │ [Warning] │ Critical information that highlights a potential risk. ╵ ╷ │ [Caution] │ Information about potential issues that require caution. ╵ █#2.8 ─#Miscellaneous ▒#2.1 ─#Emphasis This section only renders properly in smd. * and _ work the usual way, except that nesting them is possible and results in cancelling out the effects of the inner block*: ┌── md ─── │ *This is an emphasized sentence _with_ an emphasized word within*. ╵ results in: This is an emphasized sentence with an emphasized word within. ▒#2.2 ─#Em dash, En dash and Dots Like in LaΤeχ, --- refers to the em dash while -- refers to the en dash. ┌── md ─── │ --- quoted book, pages 128--34, ... ╵ gives: ╷ │ –– quoted book, pages 128–34, … ╵ ▒#2.3 ─#Thematic Breaks The rendering of this section won't work if you are not using smd. In markdown, hrules are expressed with either * or -. I chose to allow these to express different things: ┌── md ─── │ * * * ╵ results in a three-star paragraph separator, like in novels: ╷ │ * * * │ ╵ Notice it enforces a blank line before and after it. Meanwhile: ┌── md ─── │ --- │ 1: an example ╵ results in a third-width horizontal rule similar to what LaΤeχ uses in order to separate footnotes from the main page: ╷ │ ──────────────────────── │ 1: an example ╵ In order to avoid ambiguities, it is advised to have --- preceded by a blank line. A preceding blank line will be enforced in the output anyway. ▒#2.4 ─#Table of Contents* In viewer mode, a table of contents is generated at the end of stream. It gives the line numbers corresponding to each section. In less, type <number>g to go to line <number>. If needed, -N allows to toggle on/off the line numbers. This option can also be passed to smd to start less with -N enabled; in this case, the width of the numbers are taken into account when computing the screen width. It is possible to generate only the table of contents with -t. This allows, for example, to have the table of contents on one term emulator, and to browse the document easily in another. ▒#2.5 ─#tty Compatibility Mode* Some symbols are not displayed on a tty, and some colors effects (such as faint) are not properly rendered. Furthermore, OSC8 sequences do not work on such a terminal. All that is taken into account when the TERM environment variable is linux or ansi. Let me know if some terminal emulators require a similar specific treatment. ▒#2.6 ─#Embedded html Tags html comments in the form <!-- comment --> are ignored (treated as empty text) in view mode. Besides that, with the notable exception of <br/>, html tags are not managed, and therefore displayed as regular text. smd is not a browser. ▄ █#3 ─#Command Line Usage ▀──────────────────────── █#3.1 ─#Usage (as viewer) ┌── shell ─── │ smd [OPTIONS] [-2] [-t] [-R] <file.md> ╵ By default, renders the markdown file provided and shows it using less. If no argument is provided, reads stdin. If -2 is set, use 2 columns. As it was implemented with ^[[nG, horizontal scrolling with less in this mode is broken (but useless anyway), don't use it (or scroll back left if you scroll right by mistake). Just use vertical scrolling; using PGUP / PGDOWN will turn a page. Also, this implementation forces less -r, therefore /#<section_name> won't work. If -t or --toc is set, only generates the table of contents. This forces -m. If -R or --relative is set, do not make the links absolute (keep them as is). █#3.2 ─#Usage (as linter) ┌── shell ─── │ smd [OPTIONS] [-l] [-i] [-a|-f] <file.md> ╵ If -l or --linter is set, outputs re-formatted markdown. If any of -i, -a, or -f is set, -l is implied. If no argument is provided, reads stdin. If output is redirected, colors are automatically disabled. If -i or --in-place is set, the file argument is re-formatted in place. If -a or --no-alt is set, no alternate section form. If -f or --final is set, use a 1-space margin, which is easier to read, but more painful to edit. █#3.3 ─#Usage (misc) ┌── shell ─── │ smd -d | --doc | -h | --help | -v | --version ╵ If -d or --doc is set, displays the documentation (this document!) and quits. You may use any option with -d, except -i. Any other input file is silently ignored. If -h or --help is set, displays this help and quits. If -v or --version is set, displays the version number and exits. █#3.4 ─#Common Options ┌── shell ─── │ smd [-s] [-L|-D] [-w <wm>] [-j] [-p|-P] [-o <n>[!]] [-m|-N] [-n] [-r] ... ╵ If -s or --small is set, give each section of level n the layout and spacing of level n+1. The difference with -o 1 is that such a section remains declared as of level n. If -L (resp. -D), forces light (resp. dark) theme mode. The dark mode is used by default, but auto-detection works for terminal emulators that understand OSC11 (xterm, GNOME console), that set the COLORFGBG environment variable (konsole, and rxvt), or use their own protocol (kitty). If you want to always skip the xterm auto-detection (that takes 0.1s no matter what), you can simply add export COLORFGBG="0;7" for dark theme or export COLORFGBG="7;0" for light theme in your .bashrc. If -w <width_mod> or --width <width_mod> is set, modifies the default width by <width_mod> (can be positive or negative). Several -w <width_mod> will stack. If -j or --no-just is set, do not justify text. If -p or --no-par-merge is set, do not merge paragraphs. If -P or --no-punct-merge is set, do not merge paragraphs ending with punctuation symbols. If -o <n> or --hierarchy-offset <n> is set, each section of level k in the input is understood as a section of level k+<n> and declared as such. <n> is a positive integer, and is optionally followed by !. In that case, section titles of level 1 are ignored. If -m or --more is set, use more instead of less. This allows to output the stream line by line, and to keep it the output on your term. Notice that, if you are more interested in the second point, you can activate --redraw-on-quit in less. If -N or --numbers is set, display line numbers in less. If -n or --name is set, write the name(s) of the opened file(s) to stderr. This is default when multiple files are given as arguments. If -r or --no-rec is set, disable quote processing. █#3.5 ─#Environment Variables These variables can be set to configure default behaviour, for example adding the line: ┌── bash ─── │ export SMD_SEC_MAJ="32;1" ╵ to your .bashrc will make "bright green" the new default for section 1 headings. (see below) ▒#3.1 ─#Color Setting Environment Variables SMD_SEC_MAJ / SMD_SEC_MIN sets the default section level 1 major / minor color, by default 33;1 / 33;2. Similarly, we use SMD_SSEC_MAJ / SMD_SSEC_MIN for subsections (sections of level 2), and so on until SMD_SSSSSEC_MIN. Valid values are semicolon-separated lists of: • exactly one color value, • and any number of values amongst 1 (bold), 2 (faint), 3 (italics). 1 and 2 are compatible, as bold does not only affect color but also the font. The color value belongs to: • 30 (black), 31 (red), 32 (green), 33 (yellow/orange), 34 (blue), 35 (magenta), 36 (cyan), 37 (grey), 39 (default), • or 38:5:<n> where <n> a number in 0–255, • or 38;2;<r><g><b> where <r>, <g>, and <b> are numbers in 0–255. For example, SMD_SSSSEC_MAJ defaults to 34;3;2. ▒#3.2 ─#Other Environment Variables LANG_ALIASES allows to define aliases for languages names e.g.: shell:bash. • Multiple aliases are separated by spaces or commas. See section Syntax Highlighting. SMD_FLUSH_FOOT: section level at which flush footnote/references, in [0-5]. • 0 means at the end of the document. • Any other value disables footnotes/references deferring. More details are given in section References. SMD_W: The default maximum width. See section Text Justification* and Paragraph Breaks. COLORFGBG is an environment variable that is set by some term emulators, such as konsole. It can be used on other terminals, to force dark or light theme without resorting to OSC11-based auto-detection (and its 0.1s unavoidable delay). Set it to 0;7 for a light theme and 7;0 for a dark theme. ▄ █#4 ─#Bugs, Requests for Features and Future Work ▀───────────────────────────────────────────────── █#4.1 ─#Bugs and Requests for Features Fixing quickly any newly discovered bug is the top priority. Please report bugs and requests for features on the smd project codeberg page. Any unexpected behavior is a bug: it should be either fixed or better documented, so please report it. General layout style choices can (and should) be discussed and amended. As it is hard to work independently on this project without merge conflicts, please discuss your proposition in a new issue before opening a pull request. █#4.2 ─#Previous Versions and Future Improvements The first stable version is 0.7-beta-8. It is perfectly usable on most terminal emulators and true tty, and covers all usual markdown extensions. Notice that alpha lines are subject to rebasing, so only get an alpha version if you need a specific feature. ▒#v0.7.1-beta-1 • -P --no-punct-merge: do not merge par ending with punctuation. • Support kitty: ‒ theme auto-detect, ‒ emulate conceal/hide. • Manage OSC 2 (window title). • Manage enumerate alternate form. • Ignore html comments. ▒#Future v0.7.2 • lines with comments only should not be merged in pararagraphs. • Implement inclusions (see the section Coming Soon: Inclusion), and unmdbook.sed. ▒#Future v0.8 • make sure files formatted with Hongdown are stable by smd. • Improve performance on slow machines: ‒ Merge some steps of the process. • Maybe implement comments in the form: ┌── md ─── │ [comment]: <> (This is a comment, it will not be included) ╵ • Out of scope: ‒ other companion programs. ▒#Later • Improve performance on slow machines: ‒ Prematurely exit recursion to avoid spawning too much processes. • Some markdown readers needs a blank line after quotations. Should we force it? • Local links: ‒ have a --toc variant to generate all section labels. ‒ have a tool to check and re-number section labels. • Have smd rely on itself for highlighting markdown. This document would look so much better! █#4.3 ─#Future Companion Programs • Make a gutenberg2md.sed script for turning the pure text books of the Gutenberg Project into markdown. • Make a unmdbook.sed turning the link-based SUMMARY.md of mdbook into a inclusion-based markdown file. • ansifilter would be a good candidate for turning the term output into all sorts of other possible outputs. Some work is needed to make them work together, though. ▄ █#5 ─#Licence ▀───────────── This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public Licence version 3 or later. ─────────────────────────────────────────────────────────────────────────── Sed-based MarkDown viewer and linter 7 Overview ............................................................. 27 1 Install and a Note on Performance .................................. 75 2 Features .......................................................... 122 2.1 Text Justification* and Paragraph Breaks ..................... 136 2.2 Sections ..................................................... 199 2.2.1 Sections and Vertical Space* . . . . . . . . . . . . . . 201 2.2.2 Section Layout (with italics) . . . . . . . . . . . . . . 221 A fake depth-5 section title with a link inside 243 Another fake section title with bold and italics words 247 2.2.3 Automatic Section Numbering* . . . . . . . . . . . . . . 251 2.2.4 Alternate Section Form Parsing . . . . . . . . . . . . . 299 2.3 Syntax Highlighting and Code Details ......................... 337 2.3.1 Syntax Highlighting . . . . . . . . . . . . . . . . . . . 344 2.3.2 Code Details* . . . . . . . . . . . . . . . . . . . . . . 365 2.4 Indentation and Lists ........................................ 462 2.4.1 Indentation and List Nesting . . . . . . . . . . . . . . 464 2.4.2 List Numbering and Layout . . . . . . . . . . . . . . . . 529 2.5 Hyperlinks, References and Inclusion ......................... 582 2.5.1 OSC8 Links* . . . . . . . . . . . . . . . . . . . . . . . 584 2.5.2 References . . . . . . . . . . . . . . . . . . . . . . . 639 2.5.3 Coming Soon: Inclusion* . . . . . . . . . . . . . . . . . 671 2.6 Arrays ....................................................... 719 2.7 Quotes & Admonitions ......................................... 752 2.7.1 Quotes . . . . . . . . . . . . . . . . . . . . . . . . . 754 2.7.2 Admonitions . . . . . . . . . . . . . . . . . . . . . . . 768 2.8 Miscellaneous ................................................ 813 2.8.1 Emphasis . . . . . . . . . . . . . . . . . . . . . . . . 815 2.8.2 Em dash, En dash and Dots . . . . . . . . . . . . . . . . 828 2.8.3 Thematic Breaks . . . . . . . . . . . . . . . . . . . . . 839 2.8.4 Table of Contents* . . . . . . . . . . . . . . . . . . . 871 2.8.5 tty Compatibility Mode* . . . . . . . . . . . . . . . . . 885 2.8.6 Embedded html Tags . . . . . . . . . . . . . . . . . . . 895 3 Command Line Usage ................................................ 905 3.1 Usage (as viewer) ............................................ 909 3.2 Usage (as linter) ............................................ 931 3.3 Usage (misc) ................................................. 948 3.4 Common Options ............................................... 962 3.5 Environment Variables ....................................... 1007 3.5.1 Color Setting Environment Variables . . . . . . . . . . 1017 3.5.2 Other Environment Variables . . . . . . . . . . . . . . 1039 4 Bugs, Requests for Features and Future Work ...................... 1063 4.1 Bugs and Requests for Features .............................. 1067 4.2 Previous Versions and Future Improvements ................... 1084 v0.7.1-beta-1 . . . . . . . . . . . . . . . . . . . . . . . . 1093 Future v0.7.2 . . . . . . . . . . . . . . . . . . . . . . . . 1103 Future v0.8 . . . . . . . . . . . . . . . . . . . . . . . . . 1109 Later . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121 4.3 Future Companion Programs ................................... 1134 5 Licence .......................................................... 1146 ───────────────────────────────────────────────────────────────────────────