Skip to content
This repository has been archived by the owner on Apr 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #66 from AtkinsSJ/printf-again
Browse files Browse the repository at this point in the history
help+printf: Add support for extra help sections, and use them to document printf
  • Loading branch information
KernelDeimos authored Mar 22, 2024
2 parents 027e9ca + 2f600d8 commit 696178f
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 14 deletions.
35 changes: 22 additions & 13 deletions src/puter-shell/coreutils/coreutil_lib/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ export const DEFAULT_OPTIONS = {
};

export const printUsage = async (command, out, vars) => {
const { name, usage, description, args } = command;
const { name, usage, description, args, helpSections } = command;
const options = Object.create(DEFAULT_OPTIONS);
Object.assign(options, args.options);

const heading = text => {
out.write(`\x1B[34;1m${text}:\x1B[0m\n`);
const heading = async text => {
await out.write(`\x1B[34;1m${text}:\x1B[0m\n`);
};
const colorOption = text => {
return `\x1B[92m${text}\x1B[0m`;
Expand All @@ -42,7 +42,7 @@ export const printUsage = async (command, out, vars) => {
return `\x1B[91m${text}\x1B[0m`;
};

heading('Usage');
await heading('Usage');
if (!usage) {
let output = name;
if (options) {
Expand All @@ -51,26 +51,26 @@ export const printUsage = async (command, out, vars) => {
if (args.allowPositionals) {
output += ' INPUTS...';
}
out.write(` ${output}\n\n`);
await out.write(` ${output}\n\n`);
} else if (typeof usage === 'string') {
out.write(` ${usage}\n\n`);
await out.write(` ${usage}\n\n`);
} else {
for (const line of usage) {
out.write(` ${line}\n`);
await out.write(` ${line}\n`);
}
out.write('\n');
await out.write('\n');
}

if (description) {
const wrappedLines = wrapText(description, vars.size.cols);
for (const line of wrappedLines) {
out.write(`${line}\n`);
await out.write(`${line}\n`);
}
out.write(`\n`);
await out.write(`\n`);
}

if (options) {
heading('Options');
await heading('Options');

for (const optionName in options) {
let optionText = ' ';
Expand Down Expand Up @@ -119,8 +119,17 @@ export const printUsage = async (command, out, vars) => {
} else {
optionText += '\n';
}
out.write(optionText);
await out.write(optionText);
}
await out.write('\n');
}

if (helpSections) {
for (const [title, contents] of Object.entries(helpSections)) {
await heading(title);
// FIXME: Wrap the text nicely.
await out.write(contents);
await out.write('\n\n');
}
out.write('\n');
}
}
50 changes: 49 additions & 1 deletion src/puter-shell/coreutils/printf.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,59 @@ function formatOutput(parsedFormat, remainingArguments) {
}
}

function highlight(text) {
return `\x1B[92m${text}\x1B[0m`;
}

// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
export default {
name: 'printf',
usage: 'printf FORMAT [ARGUMENT...]',
description: 'Write a formatted string.',
description: 'Write a formatted string to standard output.\n\n' +
'The output is determined by FORMAT, with any escape sequences replaced, and any format strings applied to the following ARGUMENTs.\n\n' +
'FORMAT is written repeatedly until all ARGUMENTs are consumed. If FORMAT does not consume any ARGUMENTs, it is only written once.',
helpSections: {
'Escape Sequences': 'The following escape sequences are understood:\n\n' +
` ${highlight('\\\\')} A literal \\\n` +
` ${highlight('\\a')} Terminal BELL\n` +
` ${highlight('\\b')} Backspace\n` +
` ${highlight('\\f')} Form-feed\n` +
` ${highlight('\\n')} Newline\n` +
` ${highlight('\\r')} Carriage return\n` +
` ${highlight('\\t')} Horizontal tab\n` +
` ${highlight('\\v')} Vertical tab\n` +
` ${highlight('\\###')} A byte with the octal value of ### (between 1 and 3 digits)`,
'Format Strings': 'Format strings behave like C printf. ' +
'A format string is, in order: a `%`, zero or more flags, a width, a precision, and a conversion specifier. ' +
'All except the initial `%` and the conversion specifier are optional.\n\n' +
'Flags:\n\n' +
` ${highlight('-')} Left-justify the result\n` +
` ${highlight('+')} For numeric types, always include a sign character\n` +
` ${highlight('\' \'')} ${highlight('(space)')} For numeric types, include a space where the sign would go for positive numbers. Overridden by ${highlight('+')}.\n`+
` ${highlight('#')} Use alternative form, depending on the conversion:\n` +
` ${highlight('o')} Ensure result is always prefixed with a '0'\n` +
` ${highlight('x,X')} Prefix result with '0x' or '0X' respectively\n` +
` ${highlight('e,E,f,F,g,G')} Always include a decimal point. For ${highlight('g,G')}, also keep trailing 0s\n\n` +
'Width:\n\n' +
'A number, for how many characters the result should occupy.\n\n' +
'Precision:\n\n' +
'A \'.\' followed optionally by a number. If no number is specified, it is taken as 0. Effect depends on the conversion:\n\n' +
` ${highlight('d,i,o,u,x,X')} Determines the minimum number of digits\n` +
` ${highlight('e,E,f,F')} Determines the number of digits after the decimal point\n\n` +
` ${highlight('g,G')} Determines the number of significant figures\n\n` +
` ${highlight('s')} Determines the maximum number of characters to be printed\n\n` +
'Conversion specifiers:\n\n' +
` ${highlight('%')} A literal '%'\n` +
` ${highlight('s')} ARGUMENT as a string\n` +
` ${highlight('c')} The first character of ARGUMENT as a string\n` +
` ${highlight('d,i')} ARGUMENT as a number, formatted as a signed decimal integer\n` +
` ${highlight('u')} ARGUMENT as a number, formatted as an unsigned decimal integer\n` +
` ${highlight('o')} ARGUMENT as a number, formatted as an unsigned octal integer\n` +
` ${highlight('x,X')} ARGUMENT as a number, formatted as an unsigned hexadecimal integer, in lower or uppercase respectively\n` +
` ${highlight('e,E')} ARGUMENT as a number, formatted as a float in exponential notation, in lower or uppercase respectively\n` +
` ${highlight('f,F')} ARGUMENT as a number, formatted as a float in decimal notation, in lower or uppercase respectively\n` +
` ${highlight('g,G')} ARGUMENT as a number, formatted as a float in either decimal or exponential notation, in lower or uppercase respectively`,
},
args: {
$: 'simple-parser',
allowPositionals: true
Expand Down

0 comments on commit 696178f

Please sign in to comment.