feat: readme file

This commit is contained in:
ThetaDev 2024-03-14 03:11:51 +01:00
parent 441fe260ff
commit 97df2dcc44
Signed by: ThetaDev
GPG key ID: E319D3C5148D65B6
5 changed files with 1197 additions and 269 deletions

View file

@ -556,6 +556,10 @@ static const ngx_str_t img_icon_pre =
ngx_string("<img src=\"");
static const ngx_str_t img_icon_post =
ngx_string("\" alt=\"\" height=\"32\" width=\"32\">");
static const ngx_str_t footer_pre =
ngx_string("<footer class=\"markup\">");
static const ngx_str_t footer_post =
ngx_string("</footer>");
#ifdef NGX_ESCAPE_URI_COMPONENT
@ -732,6 +736,9 @@ make_content_buf(
ngx_str_t path;
ngx_dir_t dir;
ngx_buf_t *b;
u_char *readme_path = NULL;
u_char readme_md = 0;
off_t readme_file_len = 0;
static const char *sizes[] = { "EiB", "PiB", "TiB", "GiB", "MiB", "KiB", "B" };
static const int64_t exbibyte = 1024LL * 1024LL * 1024LL *
@ -904,6 +911,18 @@ make_content_buf(
if (entry->dir) n_dirs += 1;
else n_files += 1;
if (ngx_strncasecmp(entry->name.data, (u_char*) "README", 6) == 0 && (entry->name.len == 6 || entry->name.data[6] == '.')) {
if (!readme_path || ngx_strcmp(readme_path, filename) > 0) {
// readme_path = filename;
if ((readme_path = ngx_palloc(r->pool, allocated)) == NULL)
return ngx_http_fancyindex_error(r, &dir, &path);
ngx_cpystrn(readme_path, filename, allocated);
readme_file_len = entry->size;
readme_md = entry->name.len > 6 && ngx_strncasecmp(entry->name.data + 6, (u_char*) ".md", 3) == 0;
}
}
}
if (ngx_close_dir(&dir) == NGX_ERROR) {
@ -911,6 +930,33 @@ make_content_buf(
ngx_close_dir_n " \"%s\" failed", &path);
}
if (readme_path) {
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"README: %s, MD%d, len: %d", readme_path, readme_md, readme_file_len);
/*
ngx_file_t readme_file;
ngx_memzero(&readme_file, sizeof(ngx_file_t));
readme_file.fd = ngx_open_file(readme_path->data, NGX_FILE_RDONLY, 0, 0);
if (readme_file.fd == NGX_INVALID_FILE) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
"cannot open readme file \"%V\"", readme_path->data);
}
*/
/*else {
ngx_file_info_t fi;
if (ngx_fd_info(readme_file.fd, &fi) == NGX_FILE_ERROR) {
ngx_close_file(readme_file.fd);
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
"cannot get info for readme file \"%V\"", readme_path->data);
} else {
readme_file_len = ngx_file_size(&fi);
}
}*/
}
/*
* Calculate needed buffer length.
*/
@ -986,6 +1032,10 @@ make_content_buf(
if (entry[i].link) len += ngx_sizeof_ssz("-shortcut");
}
if (readme_file_len) {
len += footer_pre.len + readme_file_len + footer_post.len;
}
if ((b = ngx_create_temp_buf(r->pool, len)) == NULL)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@ -1251,6 +1301,41 @@ make_content_buf(
/* Output table bottom */
b->last = ngx_cpymem_ssz(b->last, t07_list2);
// Readme file
if (readme_file_len) {
b->last = ngx_cpymem_str(b->last, footer_pre);
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "outputting footer");
ngx_file_t file;
ngx_memzero(&file, sizeof(ngx_file_t));
file.fd = ngx_open_file(readme_path, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
if (file.fd == NGX_INVALID_FILE) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
"cannot open readme file \"%V\"", readme_path);
return NGX_ERROR;
}
file.log = r->connection->log;
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "opened file %d", file);
ssize_t n = readme_file_len;
while (n > 0) {
ssize_t rbts = ngx_read_file(&file,
b->last + file.offset,
n,
file.offset);
if (rbts == NGX_ERROR) {
ngx_close_file(file.fd);
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
"cannot read readme file \"%V\"", readme_path);
return NGX_ERROR;
}
b->last += rbts;
n -= rbts;
}
b->last = ngx_cpymem_str(b->last, footer_post);
}
*pb = b;
return NGX_OK;
}
@ -1379,8 +1464,8 @@ add_builtin_header:
out[last].buf->pos = alcf->footer.local.data;
out[last].buf->last = alcf->footer.local.data + alcf->footer.local.len;
} else {
out[last].buf->pos = (u_char*) t08_foot1;
out[last].buf->last = (u_char*) t08_foot1 + sizeof(t08_foot1) - 1;
out[last].buf->pos = (u_char*) t08_foot;
out[last].buf->last = (u_char*) t08_foot + sizeof(t08_foot) - 1;
}
out[last-1].buf->last_in_chain = 0;
@ -1441,8 +1526,8 @@ add_builtin_header:
if (out[0].buf == NULL)
return NGX_ERROR;
out[0].buf->memory = 1;
out[0].buf->pos = (u_char*) t08_foot1;
out[0].buf->last = (u_char*) t08_foot1 + sizeof(t08_foot1) - 1;
out[0].buf->pos = (u_char*) t08_foot;
out[0].buf->last = (u_char*) t08_foot + sizeof(t08_foot) - 1;
out[0].buf->last_in_chain = 1;
out[0].buf->last_buf = 1;
/* Directly send out the builtin footer */

3
t/README.md Normal file
View file

@ -0,0 +1,3 @@
Hello World
Hello World, this is me ;-)

View file

@ -1 +1,3 @@
<h1>Hello World</h1>
Hello World, this is me ;-)

View file

@ -6,130 +6,332 @@ static const u_char t01_head1[] = ""
" <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />"
" <meta name=\"viewport\" content=\"width=device-width\" />"
" <style type=\"text/css\">"
" * {"
" padding: 0;"
" margin: 0;"
" }"
" body {"
" font-family: sans-serif;"
" text-rendering: optimizespeed;"
" background-color: #f5f5f5;"
" }"
" a {"
" color: #006ed3;"
" text-decoration: none;"
" }"
" a:hover,"
" h1 a:hover {"
" color: #319cff;"
" }"
" header,"
" #summary {"
" padding: 0 20px;"
" }"
" header {"
" display: flex;"
" flex-direction: row;"
" gap: 1em;"
" padding-top: 25px;"
" padding-bottom: 15px;"
" background-color: #f2f2f2;"
" }"
" h1 {"
" font-size: 20px;"
" font-weight: normal;"
" white-space: nowrap;"
" overflow-x: hidden;"
" text-overflow: ellipsis;"
" color: #999;"
" }"
" h1 a {"
" color: #000;"
" margin: 0 4px;"
" }"
" h1 a:hover {"
" text-decoration: underline;"
" }"
" h1 a:first-child {"
" margin: 0;"
" }"
" main {"
" display: block;"
" }"
" .meta {"
" font-size: 12px;"
" font-family: Verdana, sans-serif;"
" border-bottom: 1px solid #9c9c9c;"
" padding-top: 10px;"
" padding-bottom: 10px;"
" }"
" .meta-item {"
" margin-right: 1em;"
" }"
" #filter {"
" padding: 4px;"
" border: 1px solid #ccc;"
" }"
" table {"
" width: 100%;"
" border-collapse: collapse;"
" }"
" tr {"
" border-bottom: 1px dashed #dadada;"
" }"
" tbody tr:hover {"
" background-color: #ffffec;"
" }"
" th,"
" td {"
" text-align: left;"
" padding: 10px 0;"
" }"
" th {"
" padding-top: 15px;"
" padding-bottom: 15px;"
" font-size: 16px;"
" white-space: nowrap;"
" }"
" th a {"
" color: black;"
" }"
" th svg {"
" vertical-align: middle;"
" }"
" td {"
" white-space: nowrap;"
" font-size: 14px;"
" }"
" td:nth-child(1),"
" th:nth-child(1) {"
" padding-left: 20px;"
" width: 80%;"
" }"
" td:nth-child(2),"
" th:nth-child(2) {"
" padding: 0 20px 0 20px;"
" }"
" th:nth-child(3),"
" td:nth-child(3) {"
" text-align: right;"
" padding-right: 20px;"
" }"
" td:nth-child(1) svg {"
" position: absolute;"
" }"
" td .name,"
" td .goup {"
" margin-left: 1.75em;"
" word-break: break-all;"
" overflow-wrap: break-word;"
" white-space: pre-wrap;"
" }"
" footer {"
" padding: 40px 20px;"
" font-size: 12px;"
" text-align: center;"
" }"
"* {"
" padding: 0;"
" margin: 0;"
" --color-secondary: #dedede;"
" --color-text-light: gray;"
"}"
"body {"
" font-family: sans-serif;"
" text-rendering: optimizespeed;"
" background-color: #f5f5f5;"
"}"
"a {"
" color: #006ed3;"
" text-decoration: none;"
"}"
"a:hover {"
" color: #319cff;"
"}"
"header,"
"#summary {"
" padding: 0 20px;"
"}"
"header {"
" display: flex;"
" flex-direction: row;"
" gap: 1em;"
" padding-top: 25px;"
" padding-bottom: 15px;"
" background-color: #f2f2f2;"
"}"
"header h1 {"
" font-size: 20px;"
" font-weight: normal;"
" white-space: nowrap;"
" overflow-x: hidden;"
" text-overflow: ellipsis;"
" color: #999;"
"}"
"header h1 a {"
" color: #000;"
" margin: 0 4px;"
"}"
"header h1 a:hover, footer a:hover {"
" text-decoration: underline;"
"}"
"header h1 a:first-child {"
" margin: 0;"
"}"
"main {"
" display: block;"
"}"
".meta {"
" font-size: 12px;"
" font-family: Verdana, sans-serif;"
" border-bottom: 1px solid #9c9c9c;"
" padding-top: 10px;"
" padding-bottom: 10px;"
"}"
".meta-item {"
" margin-right: 1em;"
"}"
"#filter {"
" padding: 4px;"
" border: 1px solid #ccc;"
"}"
"#list {"
" width: 100%;"
" border-collapse: collapse;"
"}"
"#list tr {"
" border-bottom: 1px dashed #dadada;"
"}"
"#list tbody tr:hover {"
" background-color: #ffffec;"
"}"
"#list th,"
"#list td {"
" text-align: left;"
" padding: 10px 0;"
"}"
"#list th {"
" padding-top: 15px;"
" padding-bottom: 15px;"
" font-size: 16px;"
" white-space: nowrap;"
"}"
"#list th a {"
" color: black;"
"}"
"#list th svg {"
" vertical-align: middle;"
"}"
"#list td {"
" white-space: nowrap;"
" font-size: 14px;"
"}"
"#list td:nth-child(1),"
"#list th:nth-child(1) {"
" padding-left: 20px;"
" width: 80%;"
"}"
"#list td:nth-child(2),"
"#list th:nth-child(2) {"
" padding: 0 20px 0 20px;"
"}"
"#list th:nth-child(3),"
"#list td:nth-child(3) {"
" text-align: right;"
" padding-right: 20px;"
"}"
"#list td:nth-child(1) svg {"
" position: absolute;"
"}"
"#list td .name,"
"#list td .goup {"
" margin-left: 1.75em;"
" word-break: break-all;"
" overflow-wrap: break-word;"
" white-space: pre-wrap;"
"}"
"footer {"
" padding: 40px 20px;"
"}"
".markup {"
" max-width: 790px;"
" word-wrap: break-word;"
" font-size: 16px;"
" overflow: hidden;"
" line-height: 1.5 !important;"
"}"
".markup > :first-child {"
" margin-top: 0 !important;"
"}"
".markup > :last-child {"
" margin-bottom: 0 !important;"
"}"
".markup h1,"
".markup h2,"
".markup h3,"
".markup h4,"
".markup h5,"
".markup h6 {"
" font-weight: 600;"
" margin-top: 24px;"
" margin-bottom: 16px;"
" line-height: 1.25;"
"}"
".markup h1 tt,"
".markup h1 code,"
".markup h2 tt,"
".markup h2 code,"
".markup h3 tt,"
".markup h3 code,"
".markup h4 tt,"
".markup h4 code,"
".markup h5 tt,"
".markup h5 code,"
".markup h6 tt,"
".markup h6 code {"
" font-size: inherit;"
"}"
".markup h1 {"
" border-bottom: 1px solid var(--color-secondary);"
" padding-bottom: 0.3em;"
" font-size: 2em;"
"}"
".markup h2 {"
" border-bottom: 1px solid var(--color-secondary);"
" padding-bottom: 0.3em;"
" font-size: 1.5em;"
"}"
".markup h3 {"
" font-size: 1.25em;"
"}"
".markup h4 {"
" font-size: 1em;"
"}"
".markup h5 {"
" font-size: 0.875em;"
"}"
".markup h6 {"
" color: var(--color-text-light);"
" font-size: 0.85em;"
"}"
".markup p,"
".markup blockquote,"
".markup details,"
".markup ul,"
".markup ol,"
".markup dl,"
".markup table,"
".markup pre {"
" margin-top: 0;"
" margin-bottom: 16px;"
"}"
".markup hr {"
" background-color: var(--color-secondary);"
" border: 0;"
" height: 4px;"
" margin: 16px 0;"
" padding: 0;"
"}"
".markup ul,"
".markup ol {"
" padding-left: 2em;"
"}"
".markup ul ul,"
".markup ul ol,"
".markup ol ol,"
".markup ol ul {"
" margin-top: 0;"
" margin-bottom: 0;"
"}"
".markup ol ol,"
".markup ul ol {"
" list-style-type: lower-roman;"
"}"
".markup li > p {"
" margin-top: 16px;"
"}"
".markup li + li {"
" margin-top: 0.25em;"
"}"
".markup dl {"
" padding: 0;"
"}"
".markup dl dt {"
" font-size: 1em;"
" font-style: italic;"
" font-weight: 600;"
" margin-top: 16px;"
" padding: 0;"
"}"
".markup dl dd {"
" margin-bottom: 16px;"
" padding: 0 16px;"
"}"
".markup blockquote {"
" color: var(--color-text-light);"
" border-left: 4px solid var(--color-secondary);"
" margin-left: 0;"
" padding: 0 15px;"
"}"
".markup blockquote > :first-child {"
" margin-top: 0;"
"}"
".markup blockquote > :last-child {"
" margin-bottom: 0;"
"}"
".markup table {"
" width: max-content;"
" max-width: 100%;"
" display: block;"
" overflow: auto;"
"}"
".markup table th {"
" font-weight: 600;"
"}"
".markup table th,"
".markup table td {"
" border: 1px solid var(--color-secondary) !important;"
" padding: 6px 13px !important;"
"}"
".markup table tr {"
" border-top: 1px solid var(--color-secondary);"
"}"
".markup table tr:nth-child(2n) {"
" background-color: var(--color-secondary);"
"}"
".markup img,"
".markup video {"
" box-sizing: initial;"
" max-width: 100%;"
"}"
".markup img[align=\"right\"],"
".markup video[align=\"right\"] {"
" padding-left: 20px;"
"}"
".markup img[align=\"left\"],"
".markup video[align=\"left\"] {"
" padding-right: 28px;"
"}"
".markup code {"
" white-space: break-spaces;"
" background-color: var(--color-secondary);"
" border-radius: 4px;"
" margin: 0;"
" padding: 0.2em 0.4em;"
" font-size: 85%;"
"}"
".markup code br {"
" display: none;"
"}"
".markup pre {"
" background-color: var(--color-secondary);"
" border-radius: 4px;"
" padding: 16px;"
" font-size: 85%;"
" line-height: 1.45;"
" margin-bottom: 16px;"
" word-break: normal;"
" word-wrap: normal;"
"}"
".markup pre code {"
" white-space: pre-wrap;"
" word-break: break-all;"
" overflow-wrap: break-word;"
" background: 0 0;"
" line-height: inherit;"
" word-wrap: normal;"
" border: 0;"
" padding: 0;"
" margin: 0;"
" display: inline;"
" font-size: 100%;"
"}"
".markup pre code:before,"
".markup pre code:after {"
" content: normal;"
"}"
".markup .ui.list .list,"
".markup ol.ui.list ol,"
".markup ul.ui.list ul {"
" padding-left: 2em;"
"}"
"\n"
" @media (max-width: 600px) {"
" td:nth-child(1) {"
" width: auto;"
@ -146,6 +348,10 @@ static const u_char t01_head1[] = ""
" }"
" }"
" @media (prefers-color-scheme: dark) {"
" * {"
" --color-secondary: #082437;"
" --color-text-light: rgb(139, 157, 169);"
" }"
" body {"
" background-color: #101010;"
" color: #dddddd;"
@ -153,11 +359,11 @@ static const u_char t01_head1[] = ""
" header {"
" background-color: #151515;"
" }"
" tbody tr:hover {"
" #list tbody tr:hover {"
" background-color: #252525;"
" }"
" header a,"
" th a {"
" header h1 a,"
" #list th a {"
" color: #dddddd;"
" }"
" a {"
@ -168,7 +374,7 @@ static const u_char t01_head1[] = ""
" h1 a:hover {"
" color: #62b2fd;"
" }"
" tr {"
" #list tr {"
" border-bottom: 1px dashed rgba(255, 255, 255, 0.12);"
" }"
" #filter {"
@ -179,6 +385,9 @@ static const u_char t01_head1[] = ""
" .meta {"
" border-bottom: 1px solid #212121;"
" }"
" footer code, footer pre {"
" background-color: rgb(8, 36, 55);"
" }"
" }"
" </style>"
;
@ -355,10 +564,7 @@ static const u_char t07_list2[] = ""
" </main>"
"\n"
;
static const u_char t08_foot1[] = ""
" <footer>"
" <p>Served with <a rel=\"noopener noreferrer\" href=\"https://nginx.org\">Nginx</a></p>"
" </footer>"
static const u_char t08_foot[] = ""
" <script>"
" var filterEl = document.getElementById(\"filter\");"
" filterEl.focus();"
@ -426,5 +632,5 @@ static const u_char t08_foot1[] = ""
+ nfi_sizeof_ssz(t06_list3) \
+ nfi_sizeof_ssz(t_parentdir_entry) \
+ nfi_sizeof_ssz(t07_list2) \
+ nfi_sizeof_ssz(t08_foot1) \
+ nfi_sizeof_ssz(t08_foot) \
)

View file

@ -5,130 +5,332 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<style type="text/css">
* {
padding: 0;
margin: 0;
}
body {
font-family: sans-serif;
text-rendering: optimizespeed;
background-color: #f5f5f5;
}
a {
color: #006ed3;
text-decoration: none;
}
a:hover,
h1 a:hover {
color: #319cff;
}
header,
#summary {
padding: 0 20px;
}
header {
display: flex;
flex-direction: row;
gap: 1em;
padding-top: 25px;
padding-bottom: 15px;
background-color: #f2f2f2;
}
h1 {
font-size: 20px;
font-weight: normal;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
color: #999;
}
h1 a {
color: #000;
margin: 0 4px;
}
h1 a:hover {
text-decoration: underline;
}
h1 a:first-child {
margin: 0;
}
main {
display: block;
}
.meta {
font-size: 12px;
font-family: Verdana, sans-serif;
border-bottom: 1px solid #9c9c9c;
padding-top: 10px;
padding-bottom: 10px;
}
.meta-item {
margin-right: 1em;
}
#filter {
padding: 4px;
border: 1px solid #ccc;
}
table {
width: 100%;
border-collapse: collapse;
}
tr {
border-bottom: 1px dashed #dadada;
}
tbody tr:hover {
background-color: #ffffec;
}
th,
td {
text-align: left;
padding: 10px 0;
}
th {
padding-top: 15px;
padding-bottom: 15px;
font-size: 16px;
white-space: nowrap;
}
th a {
color: black;
}
th svg {
vertical-align: middle;
}
td {
white-space: nowrap;
font-size: 14px;
}
td:nth-child(1),
th:nth-child(1) {
padding-left: 20px;
width: 80%;
}
td:nth-child(2),
th:nth-child(2) {
padding: 0 20px 0 20px;
}
th:nth-child(3),
td:nth-child(3) {
text-align: right;
padding-right: 20px;
}
td:nth-child(1) svg {
position: absolute;
}
td .name,
td .goup {
margin-left: 1.75em;
word-break: break-all;
overflow-wrap: break-word;
white-space: pre-wrap;
}
footer {
padding: 40px 20px;
font-size: 12px;
text-align: center;
}
* {
padding: 0;
margin: 0;
--color-secondary: #dedede;
--color-text-light: gray;
}
body {
font-family: sans-serif;
text-rendering: optimizespeed;
background-color: #f5f5f5;
}
a {
color: #006ed3;
text-decoration: none;
}
a:hover {
color: #319cff;
}
header,
#summary {
padding: 0 20px;
}
header {
display: flex;
flex-direction: row;
gap: 1em;
padding-top: 25px;
padding-bottom: 15px;
background-color: #f2f2f2;
}
header h1 {
font-size: 20px;
font-weight: normal;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
color: #999;
}
header h1 a {
color: #000;
margin: 0 4px;
}
header h1 a:hover, footer a:hover {
text-decoration: underline;
}
header h1 a:first-child {
margin: 0;
}
main {
display: block;
}
.meta {
font-size: 12px;
font-family: Verdana, sans-serif;
border-bottom: 1px solid #9c9c9c;
padding-top: 10px;
padding-bottom: 10px;
}
.meta-item {
margin-right: 1em;
}
#filter {
padding: 4px;
border: 1px solid #ccc;
}
#list {
width: 100%;
border-collapse: collapse;
}
#list tr {
border-bottom: 1px dashed #dadada;
}
#list tbody tr:hover {
background-color: #ffffec;
}
#list th,
#list td {
text-align: left;
padding: 10px 0;
}
#list th {
padding-top: 15px;
padding-bottom: 15px;
font-size: 16px;
white-space: nowrap;
}
#list th a {
color: black;
}
#list th svg {
vertical-align: middle;
}
#list td {
white-space: nowrap;
font-size: 14px;
}
#list td:nth-child(1),
#list th:nth-child(1) {
padding-left: 20px;
width: 80%;
}
#list td:nth-child(2),
#list th:nth-child(2) {
padding: 0 20px 0 20px;
}
#list th:nth-child(3),
#list td:nth-child(3) {
text-align: right;
padding-right: 20px;
}
#list td:nth-child(1) svg {
position: absolute;
}
#list td .name,
#list td .goup {
margin-left: 1.75em;
word-break: break-all;
overflow-wrap: break-word;
white-space: pre-wrap;
}
footer {
padding: 40px 20px;
}
.markup {
max-width: 790px;
word-wrap: break-word;
font-size: 16px;
overflow: hidden;
line-height: 1.5 !important;
}
.markup > :first-child {
margin-top: 0 !important;
}
.markup > :last-child {
margin-bottom: 0 !important;
}
.markup h1,
.markup h2,
.markup h3,
.markup h4,
.markup h5,
.markup h6 {
font-weight: 600;
margin-top: 24px;
margin-bottom: 16px;
line-height: 1.25;
}
.markup h1 tt,
.markup h1 code,
.markup h2 tt,
.markup h2 code,
.markup h3 tt,
.markup h3 code,
.markup h4 tt,
.markup h4 code,
.markup h5 tt,
.markup h5 code,
.markup h6 tt,
.markup h6 code {
font-size: inherit;
}
.markup h1 {
border-bottom: 1px solid var(--color-secondary);
padding-bottom: 0.3em;
font-size: 2em;
}
.markup h2 {
border-bottom: 1px solid var(--color-secondary);
padding-bottom: 0.3em;
font-size: 1.5em;
}
.markup h3 {
font-size: 1.25em;
}
.markup h4 {
font-size: 1em;
}
.markup h5 {
font-size: 0.875em;
}
.markup h6 {
color: var(--color-text-light);
font-size: 0.85em;
}
.markup p,
.markup blockquote,
.markup details,
.markup ul,
.markup ol,
.markup dl,
.markup table,
.markup pre {
margin-top: 0;
margin-bottom: 16px;
}
.markup hr {
background-color: var(--color-secondary);
border: 0;
height: 4px;
margin: 16px 0;
padding: 0;
}
.markup ul,
.markup ol {
padding-left: 2em;
}
.markup ul ul,
.markup ul ol,
.markup ol ol,
.markup ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markup ol ol,
.markup ul ol {
list-style-type: lower-roman;
}
.markup li > p {
margin-top: 16px;
}
.markup li + li {
margin-top: 0.25em;
}
.markup dl {
padding: 0;
}
.markup dl dt {
font-size: 1em;
font-style: italic;
font-weight: 600;
margin-top: 16px;
padding: 0;
}
.markup dl dd {
margin-bottom: 16px;
padding: 0 16px;
}
.markup blockquote {
color: var(--color-text-light);
border-left: 4px solid var(--color-secondary);
margin-left: 0;
padding: 0 15px;
}
.markup blockquote > :first-child {
margin-top: 0;
}
.markup blockquote > :last-child {
margin-bottom: 0;
}
.markup table {
width: max-content;
max-width: 100%;
display: block;
overflow: auto;
}
.markup table th {
font-weight: 600;
}
.markup table th,
.markup table td {
border: 1px solid var(--color-secondary) !important;
padding: 6px 13px !important;
}
.markup table tr {
border-top: 1px solid var(--color-secondary);
}
.markup table tr:nth-child(2n) {
background-color: var(--color-secondary);
}
.markup img,
.markup video {
box-sizing: initial;
max-width: 100%;
}
.markup img[align="right"],
.markup video[align="right"] {
padding-left: 20px;
}
.markup img[align="left"],
.markup video[align="left"] {
padding-right: 28px;
}
.markup code {
white-space: break-spaces;
background-color: var(--color-secondary);
border-radius: 4px;
margin: 0;
padding: 0.2em 0.4em;
font-size: 85%;
}
.markup code br {
display: none;
}
.markup pre {
background-color: var(--color-secondary);
border-radius: 4px;
padding: 16px;
font-size: 85%;
line-height: 1.45;
margin-bottom: 16px;
word-break: normal;
word-wrap: normal;
}
.markup pre code {
white-space: pre-wrap;
word-break: break-all;
overflow-wrap: break-word;
background: 0 0;
line-height: inherit;
word-wrap: normal;
border: 0;
padding: 0;
margin: 0;
display: inline;
font-size: 100%;
}
.markup pre code:before,
.markup pre code:after {
content: normal;
}
.markup .ui.list .list,
.markup ol.ui.list ol,
.markup ul.ui.list ul {
padding-left: 2em;
}
@media (max-width: 600px) {
td:nth-child(1) {
width: auto;
@ -145,6 +347,10 @@
}
}
@media (prefers-color-scheme: dark) {
* {
--color-secondary: #082437;
--color-text-light: rgb(139, 157, 169);
}
body {
background-color: #101010;
color: #dddddd;
@ -152,11 +358,11 @@
header {
background-color: #151515;
}
tbody tr:hover {
#list tbody tr:hover {
background-color: #252525;
}
header a,
th a {
header h1 a,
#list th a {
color: #dddddd;
}
a {
@ -167,7 +373,7 @@
h1 a:hover {
color: #62b2fd;
}
tr {
#list tr {
border-bottom: 1px dashed rgba(255, 255, 255, 0.12);
}
#filter {
@ -178,6 +384,9 @@
.meta {
border-bottom: 1px solid #212121;
}
footer code, footer pre {
background-color: rgb(8, 36, 55);
}
}
</style>
<!-- var NONE -->
@ -399,10 +608,433 @@ Index of /path/to/somewhere
</div>
</main>
<!-- var t08_foot1 -->
<footer>
<p>Served with <a rel="noopener noreferrer" href="https://nginx.org">Nginx</a></p>
</footer>
<!-- var NONE -->
<h1><a href="https://google.github.io/styleguide/">styleguide</a></h1>
<h1 id="markdown-style-guide">Markdown style guide</h1>
<p>Much of what makes Markdown great is the ability to write plain text, and get
great formatted output as a result. To keep the slate clean for the next author,
your Markdown should be simple and consistent with the whole corpus wherever
possible.</p>
<p>We seek to balance three goals:</p>
<ol>
<li><em>Source text is readable and portable.</em></li>
<li><em>Markdown files are maintainable over time and across teams.</em></li>
<li><em>The syntax is simple and easy to remember.</em></li>
</ol>
<p>Contents:</p>
<ol>
<li><a href="#document-layout">Document layout</a></li>
<li><a href="#character-line-limit">Character line limit</a></li>
<li><a href="#trailing-whitespace">Trailing whitespace</a></li>
<li><a href="#headings">Headings</a>
<ol>
<li><a href="#atx-style-headings">ATX-style headings</a></li>
<li><a href="#add-spacing-to-headings">Add spacing to headings</a></li>
</ol>
</li>
<li><a href="#lists">Lists</a>
<ol>
<li><a href="#use-lazy-numbering-for-long-lists">Use lazy numbering for long lists</a></li>
<li><a href="#nested-list-spacing">Nested list spacing</a></li>
</ol>
</li>
<li><a href="#code">Code</a>
<ol>
<li><a href="#inline">Inline</a></li>
<li><a href="#codeblocks">Codeblocks</a></li>
<li><a href="#declare-the-language">Declare the language</a></li>
<li><a href="#escape-newlines">Escape newlines</a></li>
<li><a href="#nest-codeblocks-within-lists">Nest codeblocks within lists</a></li>
</ol>
</li>
<li><a href="#links">Links</a>
<ol>
<li><a href="#use-informative-markdown-link-titles">Use informative Markdown link titles</a></li>
</ol>
</li>
<li><a href="#images">Images</a></li>
<li><a href="#prefer-lists-to-tables">Prefer lists to tables</a></li>
<li><a href="#strongly-prefer-markdown-to-html">Strongly prefer Markdown to HTML</a></li>
</ol>
<h2 id="document-layout">Document layout</h2>
<p>In general, most documents benefit from some variation of the following layout:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Document Title</span>
Short introduction.
[TOC]
<span class="gu">## Topic</span>
Content.
<span class="gu">## See also</span>
<span class="p">
*</span> https://link-to-more-info
</code></pre></div></div>
<ol>
<li>
<p><code class="language-plaintext highlighter-rouge"># Document Title</code>: The first heading should be a level one heading, and
should ideally be the same or nearly the same as the filename. The first
level one heading is used as the page <code class="language-plaintext highlighter-rouge">&lt;title&gt;</code>.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">author</code>: <em>Optional</em>. If youd like to claim ownership of the document or
if you are very proud of it, add yourself under the title. However,
revision history generally suffices.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">Short introduction.</code> 1-3 sentences providing a high-level overview of the
topic. Imagine yourself as a complete newbie, who landed on your “Extending
Foo” doc and needs to know the most basic assumptions you take for granted.
“What is Foo? Why would I extend it?”</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">[TOC]</code>: if you use hosting that supports table of contents, such as Gitiles,
put <code class="language-plaintext highlighter-rouge">[TOC]</code> after the short introduction. See
<a href="https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md#Table-of-contents"><code class="language-plaintext highlighter-rouge">[TOC]</code> documentation</a>.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">## Topic</code>: The rest of your headings should start from level 2.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">## See also</code>: Put miscellaneous links at the bottom for the user who wants
to know more or didnt find what she needed.</p>
</li>
</ol>
<h2 id="character-line-limit">Character line limit</h2>
<p>Obey projects character line limit wherever possible. Long URLs and tables are
the usual suspects when breaking the rule. (Headings also cant be wrapped, but
we encourage keeping them short). Otherwise, wrap your text:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Lorem ipsum dolor sit amet, nec eius volumus patrioque cu, nec et commodo
hendrerit, id nobis saperet fuisset ius.
<span class="p">
*</span> Malorum moderatius vim eu. In vix dico persecuti. Te nam saperet percipitur
interesset. See the <span class="p">[</span><span class="nv">foo docs</span><span class="p">](</span><span class="sx">https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md</span><span class="p">)</span>.
</code></pre></div></div>
<p>Often, inserting a newline before a long link preserves readability while
minimizing the overflow:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Lorem ipsum dolor sit amet. See the
<span class="p">[</span><span class="nv">foo docs</span><span class="p">](</span><span class="sx">https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md</span><span class="p">)</span>
for details.
</code></pre></div></div>
<h2 id="trailing-whitespace">Trailing whitespace</h2>
<p>Dont use trailing whitespace, use a trailing backslash.</p>
<p>The <a href="http://spec.commonmark.org/0.20/#hard-line-breaks">CommonMark spec</a> decrees
that two spaces at the end of a line should insert a <code class="language-plaintext highlighter-rouge">&lt;br /&gt;</code> tag. However, many
directories have a trailing whitespace presubmit check in place, and many IDEs
will clean it up anyway.</p>
<p>Best practice is to avoid the need for a <code class="language-plaintext highlighter-rouge">&lt;br /&gt;</code> altogether. Markdown creates
paragraph tags for you simply with newlines: get used to that.</p>
<h2 id="headings">Headings</h2>
<h3 id="atx-style-headings">ATX-style headings</h3>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gu">## Heading 2</span>
</code></pre></div></div>
<p>Headings with <code class="language-plaintext highlighter-rouge">=</code> or <code class="language-plaintext highlighter-rouge">-</code> underlines can be annoying to maintain and dont fit
with the rest of the heading syntax. The user has to ask: Does <code class="language-plaintext highlighter-rouge">---</code> mean H1 or
H2?</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">Heading - do you remember what level? DO NOT DO THIS.
---------
</span></code></pre></div></div>
<h3 id="add-spacing-to-headings">Add spacing to headings</h3>
<p>Prefer spacing after <code class="language-plaintext highlighter-rouge">#</code> and newlines before and after:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...text before.
<span class="gh"># Heading 1</span>
Text after...
</code></pre></div></div>
<p>Lack of spacing makes it a little harder to read in source:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...text before.
<span class="gh">#Heading 1</span>
Text after... DO NOT DO THIS.
</code></pre></div></div>
<h2 id="lists">Lists</h2>
<h3 id="use-lazy-numbering-for-long-lists">Use lazy numbering for long lists</h3>
<p>Markdown is smart enough to let the resulting HTML render your numbered lists
correctly. For longer lists that may change, especially long nested lists, use
“lazy” numbering:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">1.</span> Foo.
<span class="p">1.</span> Bar.
<span class="p"> 1.</span> Foofoo.
<span class="p"> 1.</span> Barbar.
<span class="p">1.</span> Baz.
</code></pre></div></div>
<p>However, if the list is small and you dont anticipate changing it, prefer fully
numbered lists, because its nicer to read in source:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">1.</span> Foo.
<span class="p">2.</span> Bar.
<span class="p">3.</span> Baz.
</code></pre></div></div>
<h3 id="nested-list-spacing">Nested list spacing</h3>
<p>When nesting lists, use a 4 space indent for both numbered and bulleted lists:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">1.</span> 2 spaces after a numbered list.
4 space indent for wrapped text.
<span class="p">2.</span> 2 spaces again.
<span class="p">
*</span> 3 spaces after a bullet.
4 space indent for wrapped text.
<span class="p"> 1.</span> 2 spaces after a numbered list.
8 space indent for the wrapped text of a nested list.
<span class="p"> 2.</span> Looks nice, don't it?
<span class="p">*</span> 3 spaces after a bullet.
</code></pre></div></div>
<p>The following works, but its very messy:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">*</span> One space,
with no indent for wrapped text.
<span class="p"> 1.</span> Irregular nesting... DO NOT DO THIS.
</code></pre></div></div>
<p>Even when theres no nesting, using the 4 space indent makes layout consistent
for wrapped text:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">*</span> Foo,
wrapped.
<span class="p">
1.</span> 2 spaces
and 4 space indenting.
<span class="p">2.</span> 2 spaces again.
</code></pre></div></div>
<p>However, when lists are small, not nested, and a single line, one space can
suffice for both kinds of lists:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">*</span> Foo
<span class="p">*</span> Bar
<span class="p">*</span> Baz.
<span class="p">
1.</span> Foo.
<span class="p">2.</span> Bar.
</code></pre></div></div>
<h2 id="code">Code</h2>
<h3 id="inline">Inline</h3>
<p>`Backticks` designate <code class="language-plaintext highlighter-rouge">inline code</code>, and will render all wrapped content
literally. Use them for short code quotations and field names:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You'll want to run <span class="sb">`really_cool_script.sh arg`</span>.
Pay attention to the <span class="sb">`foo_bar_whammy`</span> field in that table.
</code></pre></div></div>
<p>Use inline code when referring to file types in an abstract sense, rather than a
specific file:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Be sure to update your <span class="sb">`README.md`</span>!
</code></pre></div></div>
<p>Backticks are the most common approach for “escaping” Markdown metacharacters;
in most situations where escaping would be needed, code font just makes sense
anyway.</p>
<h3 id="codeblocks">Codeblocks</h3>
<p>For code quotations longer than a single line, use a codeblock:</p>
<pre>
```python
def Foo(self, bar):
self.bar = bar
```
</pre>
<h4 id="declare-the-language">Declare the language</h4>
<p>It is best practice to explicitly declare the language, so that neither the
syntax highlighter nor the next editor must guess.</p>
<h4 id="indented-codeblocks-are-sometimes-cleaner">Indented codeblocks are sometimes cleaner</h4>
<p>Four-space indenting is also interpreted as a codeblock. These can look
cleaner and be easier to read in source, but there is no way to specify the
language. We encourage their use when writing many short snippets:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You'll need to run:<span class="sb">
bazel run :thing -- --foo
</span>And then:<span class="sb">
bazel run :another_thing -- --bar
</span>And again:<span class="sb">
bazel run :yet_again -- --baz
</span></code></pre></div></div>
<h4 id="escape-newlines">Escape newlines</h4>
<p>Because most commandline snippets are intended to be copied and pasted directly
into a terminal, its best practice to escape any newlines. Use a single
backslash at the end of the line:</p>
<pre>
```shell
bazel run :target -- --flag --foo=longlonglonglonglongvalue \
--bar=anotherlonglonglonglonglonglonglonglonglonglongvalue
```
</pre>
<h4 id="nest-codeblocks-within-lists">Nest codeblocks within lists</h4>
<p>If you need a codeblock within a list, make sure to indent it so as to not break
the list:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">*</span> Bullet.<span class="sb">
```c++
int foo;
```
</span><span class="p">*</span> Next bullet.
</code></pre></div></div>
<p>You can also create a nested code block with 4 spaces. Simply indent 4
additional spaces from the list indentation:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">*</span> Bullet.<span class="sb">
int foo;
</span><span class="p">*</span> Next bullet.
</code></pre></div></div>
<h2 id="links">Links</h2>
<p>Long links make source Markdown difficult to read and break the 80 character
wrapping. <strong>Wherever possible, shorten your links</strong>.</p>
<h3 id="use-informative-markdown-link-titles">Use informative Markdown link titles</h3>
<p>Markdown link syntax allows you to set a link title, just as HTML does. Use it
wisely.</p>
<p>Titling your links as “link” or “here” tells the reader precisely nothing when
quickly scanning your doc and is a waste of space:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>See the syntax guide for more info: <span class="p">[</span><span class="nv">link</span><span class="p">](</span><span class="sx">syntax_guide.md</span><span class="p">)</span>.
Or, check out the style guide <span class="p">[</span><span class="nv">here</span><span class="p">](</span><span class="sx">style_guide.md</span><span class="p">)</span>.
DO NOT DO THIS.
</code></pre></div></div>
<p>Instead, write the sentence naturally, then go back and wrap the most
appropriate phrase with the link:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>See the <span class="p">[</span><span class="nv">syntax guide</span><span class="p">](</span><span class="sx">syntax_guide.md</span><span class="p">)</span> for more info.
Or, check out the <span class="p">[</span><span class="nv">style guide</span><span class="p">](</span><span class="sx">style_guide.md</span><span class="p">)</span>.
</code></pre></div></div>
<h2 id="images">Images</h2>
<p>Use images sparingly, and prefer simple screenshots. This guide is designed
around the idea that plain text gets users down to the business of communication
faster with less reader distraction and author procrastination. However, its
sometimes very helpful to show what you mean.</p>
<p>See <a href="https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md#Images">image syntax</a>.</p>
<h2 id="prefer-lists-to-tables">Prefer lists to tables</h2>
<p>Any tables in your Markdown should be small. Complex, large tables are difficult
to read in source and most importantly, <strong>a pain to modify later</strong>.</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Fruit | Attribute | Notes
--- | --- | --- | ---
Apple | <span class="p">[</span><span class="nv">Juicy</span><span class="p">](</span><span class="sx">https://example.com/SomeReallyReallyReallyReallyReallyReallyReallyReallyLongQuery</span><span class="p">)</span>, Firm, Sweet | Apples keep doctors away.
Banana | <span class="p">[</span><span class="nv">Convenient</span><span class="p">](</span><span class="sx">https://example.com/SomeDifferentReallyReallyReallyReallyReallyReallyReallyReallyLongQuery</span><span class="p">)</span>, Soft, Sweet | Contrary to popular belief, most apes prefer mangoes.
DO NOT DO THIS
</code></pre></div></div>
<p><a href="#lists">Lists</a> and subheadings usually suffice to present the same information
in a slightly less compact, though much more edit-friendly way:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gu">## Fruits</span>
<span class="gu">### Apple</span>
<span class="p">
*</span> <span class="p">[</span><span class="nv">Juicy</span><span class="p">](</span><span class="sx">https://SomeReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongURL</span><span class="p">)</span>
<span class="p">*</span> Firm
<span class="p">*</span> Sweet
Apples keep doctors away.
<span class="gu">### Banana</span>
<span class="p">
*</span> <span class="p">[</span><span class="nv">Convenient</span><span class="p">](</span><span class="sx">https://example.com/SomeDifferentReallyReallyReallyReallyReallyReallyReallyReallyLongQuery</span><span class="p">)</span>
<span class="p">*</span> Soft
<span class="p">*</span> Sweet
Contrary to popular belief, most apes prefer mangoes.
</code></pre></div></div>
<p>However, there are times when a small table is called for:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Transport | Favored by | Advantages
--- | --- | ---
Swallow | Coconuts | Otherwise unladen
Bicycle | Miss Gulch | Weatherproof
X-34 landspeeder | Whiny farmboys | Cheap since the X-38 came out
</code></pre></div></div>
<h2 id="strongly-prefer-markdown-to-html">Strongly prefer Markdown to HTML</h2>
<p>Please prefer standard Markdown syntax wherever possible and avoid HTML hacks.
If you cant seem to accomplish what you want, reconsider whether you really
need it. Except for <a href="#prefer-lists-to-tables">big tables</a>, Markdown meets almost
all needs already.</p>
<p>Every bit of HTML or Javascript hacking reduces the readability and portability.
This in turn limits the usefulness of integrations with
other tools, which may either present the source as plain text or render it. See
<a href="/styleguide/docguide/philosophy.html">Philosophy</a>.</p>
<p>Gitiles does not render HTML.</p>
<!-- var t08_foot -->
<script>
var filterEl = document.getElementById("filter");
filterEl.focus();