💾 Archived View for auragem.letz.dev › devlog › terminal_emphasis_strong.go captured on 2024-05-26 at 14:47:45.

View Raw

More Information

⬅️ Previous capture (2024-05-10)

-=-=-=-=-=-=-

// 2024 - Christian Lee Seibold
// License: MIT

package main

import (
	"bufio"
	"fmt"
	"strings"
	"unicode"
)

func main() {
	reader := strings.NewReader("This is **some text** to show _how_ italics ** and bold __ could _**work.**_ along with `monospace.`")
	printWithEmphasisAndStrong(bufio.NewReader(reader))
}

// Emphasis - one underscore
// Strong - two asterisks
// Monospace - one backtick (`)
func printWithEmphasisAndStrong(reader *bufio.Reader) {
	previousRune := '\n'
	inStrong := false
	inEmphasis := false
	inMonospace := false

	for {
		r, _, err := reader.ReadRune()
		if err != nil {
			// EOF - reset everything, since this should be the end of the paragraph
			fmt.Printf("\x1B[m")
			return
		}

		if r == '`' || (!inMonospace && (r == '*' || r == '_')) {
			toggleRune := r
			toggle := string(r)
			unread := true

			// Get the next rune
			r, _, err = reader.ReadRune()
			if err != nil {
				// Set rune to new line, so it registers as a whitespace.
				r = '\n'
				unread = false
			}

			// If r is an asterisk, we require two for the toggle, so read the next rune. Otherwise, if just one asterisk,
			// print the runes and continue
			if toggleRune == '*' && r == '*' {
				toggle = "**"
				r, _, err = reader.ReadRune()
				if err != nil {
					// Set rune to new line, so it registers as a whitespace.
					r = '\n'
					unread = false
				}
			} else if toggleRune == '*' {
				fmt.Printf("*")
				_ = reader.UnreadRune()
				previousRune = '*'
				continue
			}

			if (!unicode.IsSpace(r) && r != toggleRune) || (!unicode.IsSpace(previousRune) && previousRune != toggleRune) {
				switch toggleRune {
				case '`':
					if inMonospace {
						// Reset
						inMonospace = false
						fmt.Printf("\x1B[22m")
						// Since 22m disables bold *and* dim, set bold again if necessary
						if inStrong {
							fmt.Printf("\x1B[1m")
						}
					} else {
						// Set
						inMonospace = true
						fmt.Printf("\x1B[2m")
					}
				case '*':
					if inStrong {
						// Reset
						inStrong = false
						// 22m disables bold *and* dim. However, we cannot use strong inside monospace toggles, so this doesn't matter.
						fmt.Printf("\x1B[22m")
					} else {
						// Set
						inStrong = true
						fmt.Printf("\x1B[1m")
					}
				case '_':
					if inEmphasis {
						// Reset
						inEmphasis = false
						fmt.Printf("\x1B[23m")
					} else {
						// Set
						inEmphasis = true
						fmt.Printf("\x1B[3m") // Replace this with 4m for underline in terminals that don't support emphasis.
					}
				}
				_ = reader.UnreadRune()
				if unread {
					previousRune = toggleRune
				}
			} else {
				// Not a toggle, print the toggle and unread the rune
				fmt.Printf("%s", toggle)
				_ = reader.UnreadRune()
				previousRune = toggleRune
			}
		} else {
			fmt.Printf("%c", r)
			previousRune = r
		}
	}
}