src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/cmd/elvmdfmt/main.go (about)

     1  // Command elvmdfmt reformats Markdown sources.
     2  //
     3  // This command is used to reformat all Markdown files in this repo; see the
     4  // [contributor's manual] on how to use it.
     5  //
     6  // For general information about the Markdown implementation used by this
     7  // command, see [src.elv.sh/pkg/md].
     8  //
     9  // [contributor's manual]: https://github.com/elves/elvish/blob/master/CONTRIBUTING.md#formatting
    10  package main
    11  
    12  import (
    13  	"flag"
    14  	"fmt"
    15  	"html"
    16  	"io"
    17  	"os"
    18  
    19  	"src.elv.sh/pkg/diff"
    20  	"src.elv.sh/pkg/md"
    21  )
    22  
    23  var (
    24  	overwrite = flag.Bool("w", false, "write result to source file (requires -fmt)")
    25  	showDiff  = flag.Bool("d", false, "show diff")
    26  	width     = flag.Int("width", 0, "if > 0, reflow content to width")
    27  )
    28  
    29  func main() {
    30  	md.UnescapeHTML = html.UnescapeString
    31  	flag.Parse()
    32  
    33  	files := flag.Args()
    34  	if len(files) == 0 {
    35  		text, err := io.ReadAll(os.Stdin)
    36  		handleReadError("stdin", err)
    37  		result, unsupported := format(string(text))
    38  		fmt.Print(result)
    39  		handleUnsupported("stdin", unsupported)
    40  		return
    41  	}
    42  	for _, file := range files {
    43  		textBytes, err := os.ReadFile(file)
    44  		handleReadError(file, err)
    45  		text := string(textBytes)
    46  		result, unsupported := format(text)
    47  		handleUnsupported(file, unsupported)
    48  		if *overwrite {
    49  			err := os.WriteFile(file, []byte(result), 0644)
    50  			if err != nil {
    51  				fmt.Fprintf(os.Stderr, "write %s: %v\n", file, err)
    52  				os.Exit(2)
    53  			}
    54  		} else if !*showDiff {
    55  			fmt.Print(result)
    56  		}
    57  		if *showDiff {
    58  			os.Stdout.Write(diff.Diff(file+".orig", text, file, result))
    59  		}
    60  	}
    61  }
    62  
    63  func format(original string) (string, *md.FmtUnsupported) {
    64  	codec := &md.FmtCodec{Width: *width}
    65  	formatted := md.RenderString(original, codec)
    66  	return formatted, codec.Unsupported()
    67  }
    68  
    69  func handleReadError(name string, err error) {
    70  	if err != nil {
    71  		fmt.Fprintf(os.Stderr, "read %s: %v\n", name, err)
    72  		os.Exit(2)
    73  	}
    74  }
    75  
    76  func handleUnsupported(name string, u *md.FmtUnsupported) {
    77  	if u == nil {
    78  		return
    79  	}
    80  	if u.NestedEmphasisOrStrongEmphasis {
    81  		fmt.Fprintln(os.Stderr, name, "contains nested emphasis or strong emphasis")
    82  	}
    83  	if u.ConsecutiveEmphasisOrStrongEmphasis {
    84  		fmt.Fprintln(os.Stderr, name, "contains consecutive emphasis or strong emphasis")
    85  	}
    86  	os.Exit(2)
    87  }