pkg.re/essentialkaos/ek.10@v12.41.0+incompatible/usage/man/man.go (about)

     1  // Package man contains methods for man pages generation
     2  package man
     3  
     4  // ////////////////////////////////////////////////////////////////////////////////// //
     5  //                                                                                    //
     6  //                         Copyright (c) 2022 ESSENTIAL KAOS                          //
     7  //      Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0>     //
     8  //                                                                                    //
     9  // ////////////////////////////////////////////////////////////////////////////////// //
    10  
    11  import (
    12  	"fmt"
    13  	"strings"
    14  	"time"
    15  
    16  	"pkg.re/essentialkaos/ek.v12/fmtc"
    17  	"pkg.re/essentialkaos/ek.v12/timeutil"
    18  	"pkg.re/essentialkaos/ek.v12/usage"
    19  )
    20  
    21  // ////////////////////////////////////////////////////////////////////////////////// //
    22  
    23  // Generate generates man page content
    24  func Generate(info *usage.Info, about *usage.About) string {
    25  	var result string
    26  
    27  	result += genHeader(about)
    28  	result += genName(about)
    29  	result += genSynopsis(info)
    30  	result += genDescription(info)
    31  	result += genCommands(info)
    32  	result += genOptions(info)
    33  	result += genExamples(info)
    34  	result += genBugTrackerInfo(about)
    35  	result += genLicense(about)
    36  	result += genAuthor(about)
    37  
    38  	return result
    39  }
    40  
    41  // ////////////////////////////////////////////////////////////////////////////////// //
    42  
    43  // genHeader generates header part
    44  func genHeader(about *usage.About) string {
    45  	return fmt.Sprintf(
    46  		".TH %s 1 \"%s\" \"%s %s\" \"%s Manual\"\n\n",
    47  		strings.ToUpper(about.App),
    48  		timeutil.Format(time.Now(), "%d %b %Y"),
    49  		about.App,
    50  		strings.Replace(about.Version, ".", "\\&.", -1),
    51  		about.App,
    52  	)
    53  }
    54  
    55  // genName generates name part
    56  func genName(about *usage.About) string {
    57  	return fmt.Sprintf(
    58  		".SH NAME\n%s \\- %s\n",
    59  		about.App, about.Desc,
    60  	)
    61  }
    62  
    63  // genSynopsis generatest synopsis
    64  func genSynopsis(info *usage.Info) string {
    65  	result := ".SH SYNOPSIS\n.sp\n.nf\n"
    66  	result += ".B " + info.Name + " "
    67  
    68  	for index, option := range info.Options {
    69  		result += genOptionShort(option)
    70  
    71  		if index != 0 && index%4 == 0 && len(info.Options) != index+1 {
    72  			result += "\n" + strings.Repeat(" ", len(info.Name)+1)
    73  		}
    74  	}
    75  
    76  	if len(info.Commands) != 0 {
    77  		result += fmt.Sprintf("[\\fB%s\\fR] ", "COMMAND")
    78  	}
    79  
    80  	if len(info.Args) != 0 {
    81  		for _, arg := range info.Args {
    82  			result += fmt.Sprintf("\\fI%s\\fR\n", arg)
    83  		}
    84  	} else {
    85  		result += "\n"
    86  	}
    87  
    88  	return result + ".fi\n.sp\n"
    89  }
    90  
    91  // genOptions generates options part
    92  func genOptions(info *usage.Info) string {
    93  	if len(info.Options) == 0 {
    94  		return ""
    95  	}
    96  
    97  	result := ".SH OPTIONS\n"
    98  
    99  	for _, option := range info.Options {
   100  		result += genOptionLong(option)
   101  	}
   102  
   103  	return result
   104  }
   105  
   106  // genCommands generates commands part
   107  func genCommands(info *usage.Info) string {
   108  	if len(info.Commands) == 0 {
   109  		return ""
   110  	}
   111  
   112  	curGroup := ""
   113  	result := ".SH COMMANDS\n"
   114  
   115  	for _, command := range info.Commands {
   116  		if command.Group != "" && curGroup != command.Group {
   117  			result += fmt.Sprintf(".SS %s\n", command.Group)
   118  			curGroup = command.Group
   119  		}
   120  
   121  		result += ".TP\n"
   122  		result += fmt.Sprintf(".B %s", command.Name)
   123  
   124  		if len(command.Args) != 0 {
   125  			result += formatCommandArgs(command.Args)
   126  		} else {
   127  			result += "\n"
   128  		}
   129  
   130  		result += fmtc.Clean(command.Desc) + "\n"
   131  	}
   132  
   133  	return result
   134  }
   135  
   136  // genOptionShort generates short info for option
   137  func genOptionShort(option *usage.Option) string {
   138  	if option.Arg != "" {
   139  		return fmt.Sprintf(
   140  			"[\\fB\\-\\-%s\\fR=\\fI%s\\fR] ",
   141  			option.Long, strings.ToUpper(option.Arg),
   142  		)
   143  	} else {
   144  		return fmt.Sprintf("[\\fB\\-\\-%s\\fR] ", option.Long)
   145  	}
   146  }
   147  
   148  // genOptionLong generates long info for option
   149  func genOptionLong(option *usage.Option) string {
   150  	result := ".TP\n"
   151  
   152  	result += ".BR "
   153  
   154  	if option.Short != "" {
   155  		result += fmt.Sprintf("\\-%s \", \" ", option.Short)
   156  	}
   157  
   158  	result += fmt.Sprintf("\\-\\-%s", option.Long)
   159  
   160  	if option.Arg != "" {
   161  		result += fmt.Sprintf("\\fR=\\fI%s\\fR\n", strings.ToUpper(option.Arg))
   162  	} else {
   163  		result += "\n"
   164  	}
   165  
   166  	result += fmtc.Clean(option.Desc) + "\n"
   167  
   168  	return result
   169  }
   170  
   171  // genDescription generates description part
   172  func genDescription(info *usage.Info) string {
   173  	if info.Spoiler == "" {
   174  		return ""
   175  	}
   176  
   177  	return fmt.Sprintf(
   178  		".SH DESCRIPTION\n\n%s\n\n",
   179  		fmtc.Clean(info.Spoiler),
   180  	)
   181  }
   182  
   183  // genExamples generates examples part
   184  func genExamples(info *usage.Info) string {
   185  	if len(info.Examples) == 0 {
   186  		return ""
   187  	}
   188  
   189  	result := ".SH EXAMPLES\n"
   190  
   191  	for index, example := range info.Examples {
   192  		result += ".TP\n"
   193  
   194  		if example.Desc != "" {
   195  			result += ".B • " + example.Desc + "\n"
   196  		} else {
   197  			result += fmt.Sprintf(".B • Example %d\n", index+1)
   198  		}
   199  
   200  		if !example.Raw {
   201  			result += fmt.Sprintf("%s %s\n", info.Name, example.Cmd)
   202  		} else {
   203  			result += fmt.Sprintf("%s\n", example.Cmd)
   204  		}
   205  	}
   206  
   207  	return result
   208  }
   209  
   210  // genBugTrackerInfo generates bugs part
   211  func genBugTrackerInfo(about *usage.About) string {
   212  	if about.BugTracker == "" {
   213  		return ""
   214  	}
   215  
   216  	return fmt.Sprintf(
   217  		".SH BUGS\n.PD 0\n\nPlease send any comments or bug reports to <\\fB%s\\fP>.\n\n",
   218  		about.BugTracker,
   219  	)
   220  }
   221  
   222  // genLicense generates license part
   223  func genLicense(about *usage.About) string {
   224  	if about.License == "" {
   225  		return ""
   226  	}
   227  
   228  	license := about.License
   229  
   230  	license = strings.Replace(license, "<", `<\fB`, -1)
   231  	license = strings.Replace(license, ">", `\fP>`, -1)
   232  
   233  	return fmt.Sprintf(".SH LICENSE\n\n%s.\n\n", license)
   234  }
   235  
   236  // genAuthor generates author part
   237  func genAuthor(about *usage.About) string {
   238  	if about.Owner == "" {
   239  		return ""
   240  	}
   241  
   242  	if about.Year == 0 {
   243  		return fmt.Sprintf(
   244  			".SH AUTHOR\n\nCopyright (C) %d \\fB%s\\fP\n\n",
   245  			time.Now().Year(), about.Owner,
   246  		)
   247  	}
   248  
   249  	return fmt.Sprintf(
   250  		".SH AUTHOR\n\nCopyright (C) %d-%d \\fB%s\\fP\n\n",
   251  		about.Year, time.Now().Year(), about.Owner,
   252  	)
   253  }
   254  
   255  // formatCommandArgs formats command arguments
   256  func formatCommandArgs(args []string) string {
   257  	result := ""
   258  
   259  	for _, arg := range args {
   260  		if strings.HasPrefix(arg, "?") {
   261  			result += fmt.Sprintf(" \\fR%s\\fP", strings.Replace(arg, "?", "", -1))
   262  		} else {
   263  			result += fmt.Sprintf(" \\fI%s\\fP", arg)
   264  		}
   265  	}
   266  
   267  	return result + "\n"
   268  }