'use strict'
const Section = require('./section')
const tableLayout = require('table-layout')
const ansi = require('ansi-escape-sequences')
const t = require('typical')
const arrayify = require('array-back')

class OptionList extends Section {
  constructor (data) {
    super()
    /* filter out hidden definitions */
    if (data.hide && data.hide.length) {
      data.optionList = data.optionList.filter(definition => {
        return data.hide.indexOf(definition.name) === -1
      })
    }
    this.header(data.header)
    this.add(optionList(data.optionList, data.group))
    this.emptyLine()
  }
}

function optionList (definitions, group) {
  if (!definitions || (definitions && !definitions.length)) {
    throw new Error('you must pass option definitions to getUsage.optionList()')
  }
  const columns = []

  if (group === '_none') {
    definitions = definitions.filter(def => !t.isDefined(def.group))
  } else if (group) {
    definitions = definitions.filter(def => arrayify(def.group).indexOf(group) > -1)
  }

  definitions.forEach(def => {
    columns.push({
      option: getOptionNames(def, 'bold'),
      description: ansi.format(def.description)
    })
  })

  return tableLayout.lines(columns, {
    padding: { left: '  ', right: ' ' },
    columns: [
      { name: 'option', nowrap: true },
      { name: 'description', maxWidth: 80 }
    ]
  })
}

function getOptionNames (definition, optionNameStyles) {
  const names = []
  let type = definition.type ? definition.type.name.toLowerCase() : ''
  const multiple = definition.multiple ? '[]' : ''
  if (type) type = type === 'boolean' ? '' : `[underline]{${type}${multiple}}`
  type = ansi.format(definition.typeLabel || type)

  if (definition.alias) {
    names.push(ansi.format('-' + definition.alias, optionNameStyles))
  }
  names.push(ansi.format(`--${definition.name}`, optionNameStyles) + ' ' + type)
  return names.join(', ')
}

module.exports = OptionList

@@ -280,124 +280,339 @@
     
-/* filter out hidden definitions */%0A    if (data.hide && data.hide.length) %7B%0A      data.optionList = data.optionList
+let definitions = arrayify(data.optionList)%0A    const hide = arrayify(data.hide)%0A    const groups = arrayify(data.group)%0A%0A    if (!definitions.length) %7B%0A      throw new Error('you must pass some option definitions to optionList')%0A    %7D%0A%0A    /* filter out hidden definitions */%0A    if (hide.length) %7B%0A      definitions = definitions
 .fil
@@ -646,21 +646,16 @@
  return 
-data.
 hide.ind
@@ -702,23 +702,16 @@
   %7D%0A
+%0A
     
-this.header
+if 
 (dat
@@ -723,157 +723,66 @@
 der)
-%0A   
  this.
-add(optionList(data.optionList, data.group)
+header(data.header
 )%0A
+%0A
     
-this.emptyLine()%0A  %7D%0A%7D%0A%0Afunction optionList (definitions, group) %7B%0A  if (!definitions %7C%7C (
+if (groups.length) %7B%0A      
 defi
@@ -793,12 +793,10 @@
 ons 
-&& !
+= 
 defi
@@ -807,196 +807,84 @@
 ons.
-length)) %7B%0A    throw new Error('you must pass option definitions to getUsage.optionList()')%0A  %7D%0A  const columns = %5B%5D%0A%0A  if (group === '_none') %7B%0A    definitions = definitions.filter(def =%3E
+filter(def =%3E %7B%0A        const noGroupMatch = groups.indexOf('_none') %3E -1 &&
  !t.
@@ -907,124 +907,162 @@
 oup)
-)
 %0A  
-%7D else if (group) %7B%0A    definitions = definitions.filter(def =%3E arrayify(def.group).indexOf(group) %3E -1
+      const groupMatch = intersect(arrayify(def.group), groups)%0A        if (noGroupMatch %7C%7C groupMatch) return def%0A      %7D
 )%0A
+  
   %7D%0A%0A  
+ 
+ const columns = 
 defi
@@ -1073,15 +1073,11 @@
 ons.
-forEach
+map
 (def
@@ -1090,23 +1090,21 @@
     
-columns.push(%7B%0A
+  return %7B%0A  
     
@@ -1148,16 +1148,18 @@
 ,%0A      
+  
 descript
@@ -1200,19 +1200,22 @@
     
+ 
-%7D)%0A
+ %7D%0A  
   %7D)%0A%0A  
 retu
@@ -1210,23 +1210,27 @@
   %7D)%0A%0A  
-return 
+  this.add(
 tableLay
@@ -1254,16 +1254,18 @@
 , %7B%0A    
+ 
+ 
 padding:
@@ -1297,16 +1297,18 @@
  %7D,%0A    
+  
 columns:
@@ -1312,24 +1312,26 @@
 ns: %5B%0A      
+ 
+ 
 %7B name: 'opt
@@ -1348,24 +1348,26 @@
 ap: true %7D,%0A
+  
       %7B name
@@ -1406,14 +1406,45 @@
     
+  
 %5D%0A  
+ 
+ 
 %7D)
+)%0A%0A    this.emptyLine()%0A  %7D
 %0A%7D%0A%0A
@@ -1547,16 +1547,20 @@
 ion.type
+%0A   
  ? defin
@@ -1588,16 +1588,20 @@
 erCase()
+%0A   
  : ''%0A  
@@ -1660,16 +1660,22 @@
 f (type)
+ %7B%0A   
  type = 
@@ -1696,13 +1696,25 @@
 ean'
- ? ''
+%0A      ? ''%0A     
  : %60
@@ -1746,16 +1746,20 @@
 iple%7D%7D%60%0A
+  %7D%0A
   type =
@@ -2012,16 +2012,172 @@
 , ')%0A%7D%0A%0A
+function intersect (arr1, arr2) %7B%0A  return arr1.some(function (item1) %7B%0A    return arr2.some(function (item2) %7B%0A      return item1 === item2%0A    %7D)%0A  %7D)%0A%7D%0A%0A
 module.e

refactor optionList