Skip to content

Commit

Permalink
chore: started work on markdown output
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Jan 30, 2018
1 parent e784ea9 commit ff43cfd
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 27 deletions.
52 changes: 41 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export interface HelpOptions {
markdown?: boolean
}

function renderList(input: (string | undefined)[][], opts: {multiline?: boolean} = {}): string {
function renderList(input: (string | undefined)[][], opts: {maxWidth: number, multiline?: boolean}): string {
if (input.length === 0) {
return ''
}
Expand All @@ -48,15 +48,15 @@ function renderList(input: (string | undefined)[][], opts: {multiline?: boolean}
for (let [left, right] of input) {
if (!left && !right) continue
if (left) {
output += indent(wrap(left.trim(), screen.stdtermwidth - 2, {hard: true, trim: false}), 2)
output += wrap(left.trim(), opts.maxWidth, {hard: true, trim: false})
}
if (right) {
output += '\n'
output += indent(wrap(right.trim(), screen.stdtermwidth - 4, {hard: true, trim: false}), 6)
output += indent(wrap(right.trim(), opts.maxWidth - 2, {hard: true, trim: false}), 4)
}
output += '\n\n'
}
return output
return output.trim()
}
const maxLength = widestLine(input.map(i => i[0]).join('\n'))
let spacer = '\n'
Expand All @@ -71,7 +71,7 @@ function renderList(input: (string | undefined)[][], opts: {multiline?: boolean}
cur = cur.trim()
continue
}
right = wrap(right.trim(), screen.stdtermwidth - (maxLength + 4), {hard: true, trim: false})
right = wrap(right.trim(), opts.maxWidth - (maxLength + 2), {hard: true, trim: false})
// right = wrap(right.trim(), screen.stdtermwidth - (maxLength + 4), {hard: true, trim: false})
const [first, ...lines] = right!.split('\n').map(s => s.trim())
cur += ' '.repeat(maxLength - width(cur) + 2)
Expand All @@ -80,7 +80,7 @@ function renderList(input: (string | undefined)[][], opts: {multiline?: boolean}
continue
}
// if we start putting too many lines down, render in multiline format
// if (lines.length > 4) return renderList(input, {...opts, multiline: true})
if (lines.length > 4) return renderList(input, {...opts, multiline: true})
spacer = '\n\n'
cur += '\n'
cur += indent(lines.join('\n'), maxLength + 2)
Expand All @@ -95,13 +95,43 @@ function renderList(input: (string | undefined)[][], opts: {multiline?: boolean}
export default class Help {
constructor(public config: IConfig) {}

command(command: ICachedCommand, _: HelpOptions = {}): string {
command(command: ICachedCommand, opts: HelpOptions = {}): string {
const help = new CommandHelp(this.config)
const article = help.command(command)
return this.render(article)
return this.render(article, opts)
}

protected render(article: Article): string {
protected render(article: Article, opts: HelpOptions): string {
if (opts.markdown) return this.renderMarkdown(article)
return this.renderScreen(article)
}

protected renderMarkdown(article: Article): string {
const maxWidth = 120
return _([
article.title,
'='.repeat(width(article.title)),
...article.sections
.map(s => {
let body
if (s.body.length === 0) {
body = ''
} else if (_.isArray(s.body[0])) {
body = renderList(s.body as any, {maxWidth: maxWidth - 2})
} else {
body = _.castArray(s.body as string).join('\n')
body = wrap(body, maxWidth - 2, {trim: false, hard: true})
}
return _([
bold(s.heading.toUpperCase()),
indent(body, 2),
]).compact().join('\n')
})
]).compact().join('\n')
}

protected renderScreen(article: Article): string {
const maxWidth = screen.stdtermwidth
return _([
article.title,
...article.sections
Expand All @@ -110,10 +140,10 @@ export default class Help {
if (s.body.length === 0) {
body = ''
} else if (_.isArray(s.body[0])) {
body = renderList(s.body as any)
body = renderList(s.body as any, {maxWidth: maxWidth - 2})
} else {
body = _.castArray(s.body as string).join('\n')
body = wrap(body, screen.stdtermwidth - 2, {trim: false, hard: true})
body = wrap(body, maxWidth - 2, {trim: false, hard: true})
}
return _([
bold(s.heading.toUpperCase()),
Expand Down
60 changes: 44 additions & 16 deletions test/command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('command help', () => {
ss: flags.boolean({description: 'newliney\n'.repeat(4)}),
remote: flags.string({char: 'r'}),
}})
.it(ctx => expect(ctx.commandHelp).to.equal(`USAGE
.it('shows lots of output', ctx => expect(ctx.commandHelp).to.equal(`USAGE
$ dxcli apps:create [APP_NAME] [OPTIONS]
ARGUMENTS
Expand Down Expand Up @@ -83,7 +83,7 @@ ALIASES
ss: flags.boolean({description: 'newliney\n'.repeat(5)}),
remote: flags.string({char: 'r'}),
}})
.it(ctx => expect(ctx.commandHelp).to.equal(`description of apps:create
.it('shows alternate output when many lines', ctx => expect(ctx.commandHelp).to.equal(`description of apps:create
USAGE
$ dxcli apps:create [APP_NAME] [OPTIONS]
Expand All @@ -92,24 +92,52 @@ ARGUMENTS
APP_NAME app to use
OPTIONS
-f, --foo=foo foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo
barfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar
foobar
-f, --foo=foo
foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoob
arfoobarfoobarfoobarfoobarfoobarfoobarfoobar
-r, --remote=remote
--force force it force it force it force it force it force
it force it force it force it force it force it
force it force it force it force it force it force
it force it force it force it force it force it
force it force it force it force it force it force
it force it
--force
force it force it force it force it force it force it force it force
it force it force it force it force it force it force it force it
force it force it force it force it force it force it force it force
it force it force it force it force it force it force it
--ss newliney
newliney
newliney
newliney
newliney
--ss
newliney
newliney
newliney
newliney
newliney
ALIASES
$ dxcli app:init
$ dxcli create`))

test
.commandHelp(class extends Command {
static id = 'apps:create'
static title = 'description of apps:create'
static aliases = ['app:init', 'create']
static description = `some
multiline help
`
static args = [{name: 'app_name', description: 'app to use'}]
static flags = {
force: flags.boolean({description: 'forces'}),
}})
.it('outputs with title', ctx => expect(ctx.commandHelp).to.equal(`description of apps:create
USAGE
$ dxcli apps:create [APP_NAME] [OPTIONS]
ARGUMENTS
APP_NAME app to use
OPTIONS
--force forces
ALIASES
$ dxcli app:init
Expand Down
71 changes: 71 additions & 0 deletions test/markdown.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {Command as Base, flags} from '@dxcli/command'
import {ICommand} from '@dxcli/config'
import {expect, test as base} from '@dxcli/test'
import stripAnsi = require('strip-ansi')

global.columns = 80
import Help from '../src'

class Command extends Base {
async run() { return }
}

const test = base
.loadConfig()
.add('help', ctx => new Help(ctx.config))
.register('commandHelp', (command?: ICommand) => ({
run(ctx: {help: Help, commandHelp: string, expectation: string}) {
const cached = command!.convertToCached()
let help = ctx.help.command(cached, {markdown: true})
ctx.commandHelp = stripAnsi(help).split('\n').map(s => s.trimRight()).join('\n')
ctx.expectation = 'has commandHelp'
}
}))

describe('command help', () => {
test
.commandHelp(class extends Command {
static title = 'the title'
static id = 'apps:create'
static aliases = ['app:init', 'create']
static description = `some
multiline help
`
static args = [{name: 'app_name', description: 'app to use'}]
static flags = {
app: flags.string({char: 'a', hidden: true}),
foo: flags.string({char: 'f', description: 'foobar'.repeat(18)}),
force: flags.boolean({description: 'force it '.repeat(15)}),
ss: flags.boolean({description: 'newliney\n'.repeat(4)}),
remote: flags.string({char: 'r'}),
}})
.skip()
.it(ctx => expect(ctx.commandHelp).to.equal(`the title
=========
USAGE
$ dxcli apps:create [APP_NAME] [OPTIONS]
ARGUMENTS
APP_NAME app to use
OPTIONS
-f, --foo=foo foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo
barfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar
-r, --remote=remote
--force force it force it force it force it force it force
it force it force it force it force it force it
force it force it force it force it
--ss newliney
newliney
newliney
newliney
ALIASES
$ dxcli app:init
$ dxcli create`))
})

0 comments on commit ff43cfd

Please sign in to comment.