1#include "arg.h"
2#include "common.h"
3
4#include <fstream>
5#include <sstream>
6#include <string>
7
8// Export usage message (-h) to markdown format
9// Automatically update the markdown docs
10
11#define HELP_START_MARKER "<!-- HELP_START -->"
12#define HELP_END_MARKER "<!-- HELP_END -->"
13#define NOTE_MESSAGE "<!-- IMPORTANT: The list below is auto-generated by llama-gen-docs; do NOT modify it manually -->"
14
15struct md_file {
16 llama_example ex;
17 std::string fname;
18 std::string specific_section_header;
19};
20
21std::vector<md_file> md_files = {
22 {LLAMA_EXAMPLE_CLI, "tools/cli/README.md", "CLI-specific params"},
23 {LLAMA_EXAMPLE_COMPLETION, "tools/completion/README.md", "Completion-specific params"},
24 {LLAMA_EXAMPLE_SERVER, "tools/server/README.md", "Server-specific params"},
25};
26
27static void write_table_header(std::ostringstream & ss) {
28 ss << "| Argument | Explanation |\n";
29 ss << "| -------- | ----------- |\n";
30}
31
32static void write_table_entry(std::ostringstream & ss, const common_arg & opt) {
33 ss << "| `";
34 // args
35 auto all_args = opt.get_args();
36 for (const auto & arg : all_args) {
37 if (arg == all_args.front()) {
38 ss << arg;
39 if (all_args.size() > 1) ss << ", ";
40 } else {
41 ss << arg << (arg != all_args.back() ? ", " : "");
42 }
43 }
44 // value hint
45 if (opt.value_hint) {
46 std::string md_value_hint(opt.value_hint);
47 string_replace_all(md_value_hint, "|", "\\|");
48 ss << " " << md_value_hint;
49 }
50 if (opt.value_hint_2) {
51 std::string md_value_hint_2(opt.value_hint_2);
52 string_replace_all(md_value_hint_2, "|", "\\|");
53 ss << " " << md_value_hint_2;
54 }
55 // help text
56 std::string md_help(opt.help);
57 md_help = string_strip(md_help);
58 string_replace_all(md_help, "\n", "<br/>");
59 string_replace_all(md_help, "|", "\\|");
60 ss << "` | " << md_help << " |\n";
61}
62
63static void write_table(std::ostringstream & ss, std::vector<common_arg *> & opts) {
64 write_table_header(ss);
65 for (const auto & opt : opts) {
66 write_table_entry(ss, *opt);
67 }
68}
69
70static void write_help(std::ostringstream & ss, const md_file & md) {
71 common_params params;
72 auto ctx_arg = common_params_parser_init(params, md.ex);
73
74 std::vector<common_arg *> common_options;
75 std::vector<common_arg *> sparam_options;
76 std::vector<common_arg *> specific_options;
77 for (auto & opt : ctx_arg.options) {
78 // in case multiple LLAMA_EXAMPLE_* are set, we prioritize the LLAMA_EXAMPLE_* matching current example
79 if (opt.is_sparam) {
80 sparam_options.push_back(&opt);
81 } else if (opt.in_example(ctx_arg.ex)) {
82 specific_options.push_back(&opt);
83 } else {
84 common_options.push_back(&opt);
85 }
86 }
87
88 ss << HELP_START_MARKER << "\n\n";
89
90 ss << NOTE_MESSAGE << "\n\n";
91
92 ss << "### Common params\n\n";
93 write_table(ss, common_options);
94 ss << "\n\n### Sampling params\n\n";
95 write_table(ss, sparam_options);
96 ss << "\n\n### " << md.specific_section_header << "\n\n";
97 write_table(ss, specific_options);
98
99 ss << "\n" << HELP_END_MARKER;
100}
101
102int main(int, char **) {
103 for (const auto & md : md_files) {
104 std::ifstream infile(md.fname);
105 if (!infile.is_open()) {
106 fprintf(stderr, "failed to open file '%s' for reading\n", md.fname.c_str());
107 return 1;
108 }
109
110 std::ostringstream ss;
111 ss << infile.rdbuf();
112 infile.close();
113
114 std::string content = ss.str();
115
116 size_t help_start = content.find(HELP_START_MARKER);
117 size_t help_end = content.find(HELP_END_MARKER);
118
119 if (help_start == std::string::npos || help_end == std::string::npos || help_end <= help_start) {
120 fprintf(stderr, "failed to find help markers in file '%s'\n", md.fname.c_str());
121 return 1;
122 }
123
124 std::ostringstream new_help_ss;
125 write_help(new_help_ss, md);
126 std::string new_help = new_help_ss.str();
127
128 content = content.substr(0, help_start) + new_help + content.substr(help_end + strlen(HELP_END_MARKER));
129
130 std::ofstream outfile(md.fname);
131 if (!outfile.is_open()) {
132 fprintf(stderr, "failed to open file '%s' for writing\n", md.fname.c_str());
133 return 1;
134 }
135 outfile << content;
136 outfile.close();
137
138 printf("Updated help in '%s'\n", md.fname.c_str());
139 }
140
141 return 0;
142}