<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="generator" content="Asciidoctor 2.0.12"> <title>Autocomplete for Java Command Line Applications</title> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"> <style> /* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */ /* Uncomment @import statement to use as custom stylesheet */ /*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/ article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section{display:block} audio,video{display:inline-block} audio:not([controls]){display:none;height:0} html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} a{background:none} a:focus{outline:thin dotted} a:active,a:hover{outline:0} h1{font-size:2em;margin:.67em 0} abbr[title]{border-bottom:1px dotted} b,strong{font-weight:bold} dfn{font-style:italic} hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0} mark{background:#ff0;color:#000} code,kbd,pre,samp{font-family:monospace;font-size:1em} pre{white-space:pre-wrap} q{quotes:"\201C" "\201D" "\2018" "\2019"} small{font-size:80%} sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} sup{top:-.5em} sub{bottom:-.25em} img{border:0} svg:not(:root){overflow:hidden} figure{margin:0} fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} legend{border:0;padding:0} button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} button,input{line-height:normal} button,select{text-transform:none} button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} textarea{overflow:auto;vertical-align:top} table{border-collapse:collapse;border-spacing:0} *,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box} html,body{font-size:100%} body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} a:hover{cursor:pointer} img,object,embed{max-width:100%;height:auto} object,embed{height:100%} img{-ms-interpolation-mode:bicubic} .left{float:left!important} .right{float:right!important} .text-left{text-align:left!important} .text-right{text-align:right!important} .text-center{text-align:center!important} .text-justify{text-align:justify!important} .hide{display:none} img,object,svg{display:inline-block;vertical-align:middle} textarea{height:auto;min-height:50px} select{width:100%} .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0} a{color:#2156a5;text-decoration:underline;line-height:inherit} a:hover,a:focus{color:#1d4b8f} a img{border:0} p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} p aside{font-size:.875em;line-height:1.35;font-style:italic} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} h1{font-size:2.125em} h2{font-size:1.6875em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} h4,h5{font-size:1.125em} h6{font-size:1em} hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0} em,i{font-style:italic;line-height:inherit} strong,b{font-weight:bold;line-height:inherit} small{font-size:60%;line-height:inherit} code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} ul,ol{margin-left:1.5em} ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em} ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} ul.square{list-style-type:square} ul.circle{list-style-type:circle} ul.disc{list-style-type:disc} ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} dl dt{margin-bottom:.3125em;font-weight:bold} dl dd{margin-bottom:1.25em} abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help} abbr{text-transform:none} blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)} blockquote cite::before{content:"\2014 \0020"} blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)} blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} h1{font-size:2.75em} h2{font-size:2.3125em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} h4{font-size:1.4375em}} table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede;word-wrap:normal} table thead,table tfoot{background:#f7f8f7} table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} table tr.even,table tr.alt{background:#f8f8f7} table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} .center{margin-left:auto;margin-right:auto} .stretch{width:100%} .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} .clearfix::after,.float-group::after{clear:both} :not(pre).nobreak{word-wrap:normal} :not(pre).nowrap{white-space:nowrap} :not(pre).pre-wrap{white-space:pre-wrap} :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed} pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit} pre>code{display:block} pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal} em em{font-style:normal} strong strong{font-weight:400} .keyseq{color:rgba(51,51,51,.8)} kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} .keyseq kbd:first-child{margin-left:0} .keyseq kbd:last-child{margin-right:0} .menuseq,.menuref{color:#000} .menuseq b:not(.caret),.menuref{font-weight:inherit} .menuseq{word-spacing:-.02em} .menuseq b.caret{font-size:1.25em;line-height:.8} .menuseq i.caret{font-weight:bold;text-align:center;width:.45em} b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} b.button::before{content:"[";padding:0 3px 0 2px} b.button::after{content:"]";padding:0 2px 0 3px} p a>code:hover{color:rgba(0,0,0,.9)} #header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} #header::after,#content::after,#footnotes::after,#footer::after{clear:both} #content{margin-top:1.25em} #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} #header .details br{display:none} #header .details br+span::before{content:"\00a0\2013\00a0"} #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} #header .details br+span#revremark::before{content:"\00a0|\00a0"} #header #revnumber{text-transform:capitalize} #header #revnumber::after{content:"\00a0"} #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} #toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em} #toc>ul{margin-left:.125em} #toc ul.sectlevel0>li>a{font-style:italic} #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} #toc li{line-height:1.3334;margin-top:.3334em} #toc a{text-decoration:none} #toc a:active{text-decoration:underline} #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} #toc.toc2 ul ul{margin-left:0;padding-left:1em} #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} body.toc2.toc-right{padding-left:0;padding-right:15em} body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}} @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} #toc.toc2{width:20em} #toc.toc2 #toctitle{font-size:1.375em} #toc.toc2>ul{font-size:.95em} #toc.toc2 ul ul{padding-left:1.25em} body.toc2.toc-right{padding-left:0;padding-right:20em}} #content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} #content #toc>:first-child{margin-top:0} #content #toc>:last-child{margin-bottom:0} #footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em} #footer-text{color:rgba(255,255,255,.8);line-height:1.44} #content{margin-bottom:.625em} .sect1{padding-bottom:.625em} @media screen and (min-width:768px){#content{margin-bottom:1.25em} .sect1{padding-bottom:1.25em}} .sect1:last-child{padding-bottom:0} .sect1+.sect1{border-top:1px solid #e7e7e9} #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} details>summary:first-of-type{cursor:pointer;display:list-item;outline:none;margin-bottom:.75em} .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} .paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)} table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit} .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} .admonitionblock>table td.icon{text-align:center;width:80px} .admonitionblock>table td.icon img{max-width:none} .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere} .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} .exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px} .exampleblock>.content>:first-child{margin-top:0} .exampleblock>.content>:last-child{margin-bottom:0} .sidebarblock{border-style:solid;border-width:1px;border-color:#dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;-webkit-border-radius:4px;border-radius:4px} .sidebarblock>:first-child{margin-top:0} .sidebarblock>:last-child{margin-bottom:0} .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} .exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} .literalblock pre,.listingblock>.content>pre{-webkit-border-radius:4px;border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em} @media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}} @media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}} .literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class="highlight"],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8} .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)} .listingblock>.content{position:relative} .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5} .listingblock:hover code[data-lang]::before{display:block} .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5} .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} .listingblock pre.highlightjs{padding:0} .listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px} .listingblock pre.prettyprint{border-width:0} .prettyprint{background:#f7f7f8} pre.prettyprint .linenums{line-height:1.45;margin-left:2em} pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0} pre.prettyprint li code[data-lang]::before{opacity:1} pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none} table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none} table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal} table.linenotable td.code{padding-left:.75em} table.linenotable td.linenos{border-right:1px solid currentColor;opacity:.35;padding-right:.5em} pre.pygments .lineno{border-right:1px solid currentColor;opacity:.35;display:inline-block;margin-right:.75em} pre.pygments .lineno::before{content:"";margin-right:-.125em} .quoteblock{margin:0 1em 1.25em 1.5em;display:table} .quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em} .quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} .quoteblock blockquote{margin:0;padding:0;border:0} .quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} .quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right} .verseblock{margin:0 1em 1.25em} .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} .verseblock pre strong{font-weight:400} .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} .quoteblock .attribution br,.verseblock .attribution br{display:none} .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0} .quoteblock.abstract{margin:0 1em 1.25em;display:block} .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} .quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf} .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0} .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem} .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0} p.tableblock:last-child{margin-bottom:0} td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere} td.tableblock>.content>:last-child{margin-bottom:-1.25em} table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} table.grid-all>*>tr>*{border-width:1px} table.grid-cols>*>tr>*{border-width:0 1px} table.grid-rows>*>tr>*{border-width:1px 0} table.frame-all{border-width:1px} table.frame-ends{border-width:1px 0} table.frame-sides{border-width:0 1px} table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0} table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0} table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0} table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0} table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd),table.stripes-even tr:nth-of-type(even),table.stripes-hover tr:hover{background:#f8f8f7} th.halign-left,td.halign-left{text-align:left} th.halign-right,td.halign-right{text-align:right} th.halign-center,td.halign-center{text-align:center} th.valign-top,td.valign-top{vertical-align:top} th.valign-bottom,td.valign-bottom{vertical-align:bottom} th.valign-middle,td.valign-middle{vertical-align:middle} table thead th,table tfoot th{font-weight:bold} tbody tr th{background:#f7f8f7} tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} p.tableblock>code:only-child{background:none;padding:0} p.tableblock{font-size:1em} ol{margin-left:1.75em} ul li ol{margin-left:1.5em} dl dd{margin-left:1.125em} dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} ul.unstyled,ol.unstyled{margin-left:0} ul.checklist{margin-left:.625em} ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em} ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} ul.inline>li{margin-left:1.25em} .unstyled dl dt{font-weight:400;font-style:normal} ol.arabic{list-style-type:decimal} ol.decimal{list-style-type:decimal-leading-zero} ol.loweralpha{list-style-type:lower-alpha} ol.upperalpha{list-style-type:upper-alpha} ol.lowerroman{list-style-type:lower-roman} ol.upperroman{list-style-type:upper-roman} ol.lowergreek{list-style-type:lower-greek} .hdlist>table,.colist>table{border:0;background:none} .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} td.hdlist1{font-weight:bold;padding-bottom:1.25em} td.hdlist2{word-wrap:anywhere} .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} .colist td:not([class]):first-child img{max-width:none} .colist td:not([class]):last-child{padding:.25em 0} .thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd} .imageblock.left{margin:.25em .625em 1.25em 0} .imageblock.right{margin:.25em 0 1.25em .625em} .imageblock>.title{margin-bottom:0} .imageblock.thumb,.imageblock.th{border-width:6px} .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} .image.left{margin-right:.625em} .image.right{margin-left:.625em} a.image{text-decoration:none;display:inline-block} a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} #footnotes .footnote:last-of-type{margin-bottom:0} #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} .gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} .gist .file-data>table td.line-data{width:99%} div.unbreakable{page-break-inside:avoid} .big{font-size:larger} .small{font-size:smaller} .underline{text-decoration:underline} .overline{text-decoration:overline} .line-through{text-decoration:line-through} .aqua{color:#00bfbf} .aqua-background{background:#00fafa} .black{color:#000} .black-background{background:#000} .blue{color:#0000bf} .blue-background{background:#0000fa} .fuchsia{color:#bf00bf} .fuchsia-background{background:#fa00fa} .gray{color:#606060} .gray-background{background:#7d7d7d} .green{color:#006000} .green-background{background:#007d00} .lime{color:#00bf00} .lime-background{background:#00fa00} .maroon{color:#600000} .maroon-background{background:#7d0000} .navy{color:#000060} .navy-background{background:#00007d} .olive{color:#606000} .olive-background{background:#7d7d00} .purple{color:#600060} .purple-background{background:#7d007d} .red{color:#bf0000} .red-background{background:#fa0000} .silver{color:#909090} .silver-background{background:#bcbcbc} .teal{color:#006060} .teal-background{background:#007d7d} .white{color:#bfbfbf} .white-background{background:#fafafa} .yellow{color:#bfbf00} .yellow-background{background:#fafa00} span.icon>.fa{cursor:default} a span.icon>.fa{cursor:inherit} .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);-webkit-border-radius:50%;border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} .conum[data-value] *{color:#fff!important} .conum[data-value]+b{display:none} .conum[data-value]::after{content:attr(data-value)} pre .conum[data-value]{position:relative;top:-.125em} b.conum *{color:inherit!important} .conum:not([data-value]):empty{display:none} dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} h1,h2,p,td.content,span.alt{letter-spacing:-.01em} p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} p,blockquote,dt,td.content,span.alt{font-size:1.0625rem} p{margin-bottom:1.25rem} .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} .exampleblock>.content{background:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc} .print-only{display:none!important} @page{margin:1.25cm .75cm} @media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important} html{font-size:80%} a{color:inherit!important;text-decoration:underline!important} a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} abbr[title]::after{content:" (" attr(title) ")"} pre,blockquote,tr,img,object,svg{page-break-inside:avoid} thead{display:table-header-group} svg{max-width:100%} p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} #header,#content,#footnotes,#footer{max-width:none} #toc,.sidebarblock,.exampleblock>.content{background:none!important} #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} body.book #header{text-align:center} body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} body.book #header .details{border:0!important;display:block;padding:0!important} body.book #header .details span:first-child{margin-left:0!important} body.book #header .details br{display:block} body.book #header .details br+span::before{content:none!important} body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} .listingblock code[data-lang]::before{display:block} #footer{padding:0 .9375em} .hide-on-print{display:none!important} .print-only{display:block!important} .hide-for-print{display:none!important} .show-for-print{display:inherit!important}} @media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem} .sect1{padding:0!important} .sect1+.sect1{border:0} #footer{background:none} #footer-text{color:rgba(0,0,0,.6);font-size:.9em}} @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <style> /* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */ pre.CodeRay{background:#f7f7f8} .CodeRay .line-numbers{border-right:1px solid currentColor;opacity:.35;padding:0 .5em 0 0} .CodeRay span.line-numbers{display:inline-block;margin-right:.75em} .CodeRay .line-numbers strong{color:#000} table.CodeRay{border-collapse:separate;border:0;margin-bottom:0;background:none} table.CodeRay td{vertical-align:top;line-height:inherit} table.CodeRay td.line-numbers{text-align:right} table.CodeRay td.code{padding:0 0 0 .75em} .CodeRay .debug{color:#fff !important;background:#000080 !important} .CodeRay .annotation{color:#007} .CodeRay .attribute-name{color:#000080} .CodeRay .attribute-value{color:#700} .CodeRay .binary{color:#509} .CodeRay .comment{color:#998;font-style:italic} .CodeRay .char{color:#04d} .CodeRay .char .content{color:#04d} .CodeRay .char .delimiter{color:#039} .CodeRay .class{color:#458;font-weight:bold} .CodeRay .complex{color:#a08} .CodeRay .constant,.CodeRay .predefined-constant{color:#008080} .CodeRay .color{color:#099} .CodeRay .class-variable{color:#369} .CodeRay .decorator{color:#b0b} .CodeRay .definition{color:#099} .CodeRay .delimiter{color:#000} .CodeRay .doc{color:#970} .CodeRay .doctype{color:#34b} .CodeRay .doc-string{color:#d42} .CodeRay .escape{color:#666} .CodeRay .entity{color:#800} .CodeRay .error{color:#808} .CodeRay .exception{color:inherit} .CodeRay .filename{color:#099} .CodeRay .function{color:#900;font-weight:bold} .CodeRay .global-variable{color:#008080} .CodeRay .hex{color:#058} .CodeRay .integer,.CodeRay .float{color:#099} .CodeRay .include{color:#555} .CodeRay .inline{color:#000} .CodeRay .inline .inline{background:#ccc} .CodeRay .inline .inline .inline{background:#bbb} .CodeRay .inline .inline-delimiter{color:#d14} .CodeRay .inline-delimiter{color:#d14} .CodeRay .important{color:#555;font-weight:bold} .CodeRay .interpreted{color:#b2b} .CodeRay .instance-variable{color:#008080} .CodeRay .label{color:#970} .CodeRay .local-variable{color:#963} .CodeRay .octal{color:#40e} .CodeRay .predefined{color:#369} .CodeRay .preprocessor{color:#579} .CodeRay .pseudo-class{color:#555} .CodeRay .directive{font-weight:bold} .CodeRay .type{font-weight:bold} .CodeRay .predefined-type{color:inherit} .CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} .CodeRay .key{color:#808} .CodeRay .key .delimiter{color:#606} .CodeRay .key .char{color:#80f} .CodeRay .value{color:#088} .CodeRay .regexp .delimiter{color:#808} .CodeRay .regexp .content{color:#808} .CodeRay .regexp .modifier{color:#808} .CodeRay .regexp .char{color:#d14} .CodeRay .regexp .function{color:#404;font-weight:bold} .CodeRay .string{color:#d20} .CodeRay .string .string .string{background:#ffd0d0} .CodeRay .string .content{color:#d14} .CodeRay .string .char{color:#d14} .CodeRay .string .delimiter{color:#d14} .CodeRay .shell{color:#d14} .CodeRay .shell .delimiter{color:#d14} .CodeRay .symbol{color:#990073} .CodeRay .symbol .content{color:#a60} .CodeRay .symbol .delimiter{color:#630} .CodeRay .tag{color:#008080} .CodeRay .tag-special{color:#d70} .CodeRay .variable{color:#036} .CodeRay .insert{background:#afa} .CodeRay .delete{background:#faa} .CodeRay .change{color:#aaf;background:#007} .CodeRay .head{color:#f8f;background:#505} .CodeRay .insert .insert{color:#080} .CodeRay .delete .delete{color:#800} .CodeRay .change .change{color:#66f} .CodeRay .head .head{color:#f4f} </style> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous" ></script> <script> /*! * clipboard.js v2.0.6 * https://clipboardjs.com/ * * Licensed MIT © Zeno Rocha */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["ClipboardJS"] = factory(); else root["ClipboardJS"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 6); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { function select(element) { var selectedText; if (element.nodeName === 'SELECT') { element.focus(); selectedText = element.value; } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { var isReadOnly = element.hasAttribute('readonly'); if (!isReadOnly) { element.setAttribute('readonly', ''); } element.select(); element.setSelectionRange(0, element.value.length); if (!isReadOnly) { element.removeAttribute('readonly'); } selectedText = element.value; } else { if (element.hasAttribute('contenteditable')) { element.focus(); } var selection = window.getSelection(); var range = document.createRange(); range.selectNodeContents(element); selection.removeAllRanges(); selection.addRange(range); selectedText = selection.toString(); } return selectedText; } module.exports = select; /***/ }), /* 1 */ /***/ (function(module, exports) { function E () { // Keep this empty so it's easier to inherit from // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) } E.prototype = { on: function (name, callback, ctx) { var e = this.e || (this.e = {}); (e[name] || (e[name] = [])).push({ fn: callback, ctx: ctx }); return this; }, once: function (name, callback, ctx) { var self = this; function listener () { self.off(name, listener); callback.apply(ctx, arguments); }; listener._ = callback return this.on(name, listener, ctx); }, emit: function (name) { var data = [].slice.call(arguments, 1); var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); var i = 0; var len = evtArr.length; for (i; i < len; i++) { evtArr[i].fn.apply(evtArr[i].ctx, data); } return this; }, off: function (name, callback) { var e = this.e || (this.e = {}); var evts = e[name]; var liveEvents = []; if (evts && callback) { for (var i = 0, len = evts.length; i < len; i++) { if (evts[i].fn !== callback && evts[i].fn._ !== callback) liveEvents.push(evts[i]); } } // Remove event from queue to prevent memory leak // Suggested by https://github.com/lazd // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 (liveEvents.length) ? e[name] = liveEvents : delete e[name]; return this; } }; module.exports = E; module.exports.TinyEmitter = E; /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { var is = __webpack_require__(3); var delegate = __webpack_require__(4); /** * Validates all params and calls the right * listener function based on its target type. * * @param {String|HTMLElement|HTMLCollection|NodeList} target * @param {String} type * @param {Function} callback * @return {Object} */ function listen(target, type, callback) { if (!target && !type && !callback) { throw new Error('Missing required arguments'); } if (!is.string(type)) { throw new TypeError('Second argument must be a String'); } if (!is.fn(callback)) { throw new TypeError('Third argument must be a Function'); } if (is.node(target)) { return listenNode(target, type, callback); } else if (is.nodeList(target)) { return listenNodeList(target, type, callback); } else if (is.string(target)) { return listenSelector(target, type, callback); } else { throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); } } /** * Adds an event listener to a HTML element * and returns a remove listener function. * * @param {HTMLElement} node * @param {String} type * @param {Function} callback * @return {Object} */ function listenNode(node, type, callback) { node.addEventListener(type, callback); return { destroy: function() { node.removeEventListener(type, callback); } } } /** * Add an event listener to a list of HTML elements * and returns a remove listener function. * * @param {NodeList|HTMLCollection} nodeList * @param {String} type * @param {Function} callback * @return {Object} */ function listenNodeList(nodeList, type, callback) { Array.prototype.forEach.call(nodeList, function(node) { node.addEventListener(type, callback); }); return { destroy: function() { Array.prototype.forEach.call(nodeList, function(node) { node.removeEventListener(type, callback); }); } } } /** * Add an event listener to a selector * and returns a remove listener function. * * @param {String} selector * @param {String} type * @param {Function} callback * @return {Object} */ function listenSelector(selector, type, callback) { return delegate(document.body, selector, type, callback); } module.exports = listen; /***/ }), /* 3 */ /***/ (function(module, exports) { /** * Check if argument is a HTML element. * * @param {Object} value * @return {Boolean} */ exports.node = function(value) { return value !== undefined && value instanceof HTMLElement && value.nodeType === 1; }; /** * Check if argument is a list of HTML elements. * * @param {Object} value * @return {Boolean} */ exports.nodeList = function(value) { var type = Object.prototype.toString.call(value); return value !== undefined && (type === '[object NodeList]' || type === '[object HTMLCollection]') && ('length' in value) && (value.length === 0 || exports.node(value[0])); }; /** * Check if argument is a string. * * @param {Object} value * @return {Boolean} */ exports.string = function(value) { return typeof value === 'string' || value instanceof String; }; /** * Check if argument is a function. * * @param {Object} value * @return {Boolean} */ exports.fn = function(value) { var type = Object.prototype.toString.call(value); return type === '[object Function]'; }; /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { var closest = __webpack_require__(5); /** * Delegates event to a selector. * * @param {Element} element * @param {String} selector * @param {String} type * @param {Function} callback * @param {Boolean} useCapture * @return {Object} */ function _delegate(element, selector, type, callback, useCapture) { var listenerFn = listener.apply(this, arguments); element.addEventListener(type, listenerFn, useCapture); return { destroy: function() { element.removeEventListener(type, listenerFn, useCapture); } } } /** * Delegates event to a selector. * * @param {Element|String|Array} [elements] * @param {String} selector * @param {String} type * @param {Function} callback * @param {Boolean} useCapture * @return {Object} */ function delegate(elements, selector, type, callback, useCapture) { // Handle the regular Element usage if (typeof elements.addEventListener === 'function') { return _delegate.apply(null, arguments); } // Handle Element-less usage, it defaults to global delegation if (typeof type === 'function') { // Use `document` as the first parameter, then apply arguments // This is a short way to .unshift `arguments` without running into deoptimizations return _delegate.bind(null, document).apply(null, arguments); } // Handle Selector-based usage if (typeof elements === 'string') { elements = document.querySelectorAll(elements); } // Handle Array-like based usage return Array.prototype.map.call(elements, function (element) { return _delegate(element, selector, type, callback, useCapture); }); } /** * Finds closest match and invokes callback. * * @param {Element} element * @param {String} selector * @param {String} type * @param {Function} callback * @return {Function} */ function listener(element, selector, type, callback) { return function(e) { e.delegateTarget = closest(e.target, selector); if (e.delegateTarget) { callback.call(element, e); } } } module.exports = delegate; /***/ }), /* 5 */ /***/ (function(module, exports) { var DOCUMENT_NODE_TYPE = 9; /** * A polyfill for Element.matches() */ if (typeof Element !== 'undefined' && !Element.prototype.matches) { var proto = Element.prototype; proto.matches = proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector; } /** * Finds the closest parent that matches a selector. * * @param {Element} element * @param {String} selector * @return {Function} */ function closest (element, selector) { while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { if (typeof element.matches === 'function' && element.matches(selector)) { return element; } element = element.parentNode; } } module.exports = closest; /***/ }), /* 6 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); // EXTERNAL MODULE: ./node_modules/select/src/select.js var src_select = __webpack_require__(0); var select_default = /*#__PURE__*/__webpack_require__.n(src_select); // CONCATENATED MODULE: ./src/clipboard-action.js var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Inner class which performs selection from either `text` or `target` * properties and then executes copy or cut operations. */ var clipboard_action_ClipboardAction = function () { /** * @param {Object} options */ function ClipboardAction(options) { _classCallCheck(this, ClipboardAction); this.resolveOptions(options); this.initSelection(); } /** * Defines base properties passed from constructor. * @param {Object} options */ _createClass(ClipboardAction, [{ key: 'resolveOptions', value: function resolveOptions() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.action = options.action; this.container = options.container; this.emitter = options.emitter; this.target = options.target; this.text = options.text; this.trigger = options.trigger; this.selectedText = ''; } /** * Decides which selection strategy is going to be applied based * on the existence of `text` and `target` properties. */ }, { key: 'initSelection', value: function initSelection() { if (this.text) { this.selectFake(); } else if (this.target) { this.selectTarget(); } } /** * Creates a fake textarea element, sets its value from `text` property, * and makes a selection on it. */ }, { key: 'selectFake', value: function selectFake() { var _this = this; var isRTL = document.documentElement.getAttribute('dir') == 'rtl'; this.removeFake(); this.fakeHandlerCallback = function () { return _this.removeFake(); }; this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true; this.fakeElem = document.createElement('textarea'); // Prevent zooming on iOS this.fakeElem.style.fontSize = '12pt'; // Reset box model this.fakeElem.style.border = '0'; this.fakeElem.style.padding = '0'; this.fakeElem.style.margin = '0'; // Move element out of screen horizontally this.fakeElem.style.position = 'absolute'; this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically var yPosition = window.pageYOffset || document.documentElement.scrollTop; this.fakeElem.style.top = yPosition + 'px'; this.fakeElem.setAttribute('readonly', ''); this.fakeElem.value = this.text; this.container.appendChild(this.fakeElem); this.selectedText = select_default()(this.fakeElem); this.copyText(); } /** * Only removes the fake element after another click event, that way * a user can hit `Ctrl+C` to copy because selection still exists. */ }, { key: 'removeFake', value: function removeFake() { if (this.fakeHandler) { this.container.removeEventListener('click', this.fakeHandlerCallback); this.fakeHandler = null; this.fakeHandlerCallback = null; } if (this.fakeElem) { this.container.removeChild(this.fakeElem); this.fakeElem = null; } } /** * Selects the content from element passed on `target` property. */ }, { key: 'selectTarget', value: function selectTarget() { this.selectedText = select_default()(this.target); this.copyText(); } /** * Executes the copy operation based on the current selection. */ }, { key: 'copyText', value: function copyText() { var succeeded = void 0; try { succeeded = document.execCommand(this.action); } catch (err) { succeeded = false; } this.handleResult(succeeded); } /** * Fires an event based on the copy operation result. * @param {Boolean} succeeded */ }, { key: 'handleResult', value: function handleResult(succeeded) { this.emitter.emit(succeeded ? 'success' : 'error', { action: this.action, text: this.selectedText, trigger: this.trigger, clearSelection: this.clearSelection.bind(this) }); } /** * Moves focus away from `target` and back to the trigger, removes current selection. */ }, { key: 'clearSelection', value: function clearSelection() { if (this.trigger) { this.trigger.focus(); } document.activeElement.blur(); window.getSelection().removeAllRanges(); } /** * Sets the `action` to be performed which can be either 'copy' or 'cut'. * @param {String} action */ }, { key: 'destroy', /** * Destroy lifecycle. */ value: function destroy() { this.removeFake(); } }, { key: 'action', set: function set() { var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy'; this._action = action; if (this._action !== 'copy' && this._action !== 'cut') { throw new Error('Invalid "action" value, use either "copy" or "cut"'); } } /** * Gets the `action` property. * @return {String} */ , get: function get() { return this._action; } /** * Sets the `target` property using an element * that will be have its content copied. * @param {Element} target */ }, { key: 'target', set: function set(target) { if (target !== undefined) { if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) { if (this.action === 'copy' && target.hasAttribute('disabled')) { throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); } if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); } this._target = target; } else { throw new Error('Invalid "target" value, use a valid Element'); } } } /** * Gets the `target` property. * @return {String|HTMLElement} */ , get: function get() { return this._target; } }]); return ClipboardAction; }(); /* harmony default export */ var clipboard_action = (clipboard_action_ClipboardAction); // EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js var tiny_emitter = __webpack_require__(1); var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter); // EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js var listen = __webpack_require__(2); var listen_default = /*#__PURE__*/__webpack_require__.n(listen); // CONCATENATED MODULE: ./src/clipboard.js var clipboard_typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var clipboard_createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** * Base class which takes one or more elements, adds event listeners to them, * and instantiates a new `ClipboardAction` on each click. */ var clipboard_Clipboard = function (_Emitter) { _inherits(Clipboard, _Emitter); /** * @param {String|HTMLElement|HTMLCollection|NodeList} trigger * @param {Object} options */ function Clipboard(trigger, options) { clipboard_classCallCheck(this, Clipboard); var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this)); _this.resolveOptions(options); _this.listenClick(trigger); return _this; } /** * Defines if attributes would be resolved using internal setter functions * or custom functions that were passed in the constructor. * @param {Object} options */ clipboard_createClass(Clipboard, [{ key: 'resolveOptions', value: function resolveOptions() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.action = typeof options.action === 'function' ? options.action : this.defaultAction; this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; this.text = typeof options.text === 'function' ? options.text : this.defaultText; this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body; } /** * Adds a click event listener to the passed trigger. * @param {String|HTMLElement|HTMLCollection|NodeList} trigger */ }, { key: 'listenClick', value: function listenClick(trigger) { var _this2 = this; this.listener = listen_default()(trigger, 'click', function (e) { return _this2.onClick(e); }); } /** * Defines a new `ClipboardAction` on each click event. * @param {Event} e */ }, { key: 'onClick', value: function onClick(e) { var trigger = e.delegateTarget || e.currentTarget; if (this.clipboardAction) { this.clipboardAction = null; } this.clipboardAction = new clipboard_action({ action: this.action(trigger), target: this.target(trigger), text: this.text(trigger), container: this.container, trigger: trigger, emitter: this }); } /** * Default `action` lookup function. * @param {Element} trigger */ }, { key: 'defaultAction', value: function defaultAction(trigger) { return getAttributeValue('action', trigger); } /** * Default `target` lookup function. * @param {Element} trigger */ }, { key: 'defaultTarget', value: function defaultTarget(trigger) { var selector = getAttributeValue('target', trigger); if (selector) { return document.querySelector(selector); } } /** * Returns the support of the given action, or all actions if no action is * given. * @param {String} [action] */ }, { key: 'defaultText', /** * Default `text` lookup function. * @param {Element} trigger */ value: function defaultText(trigger) { return getAttributeValue('text', trigger); } /** * Destroy lifecycle. */ }, { key: 'destroy', value: function destroy() { this.listener.destroy(); if (this.clipboardAction) { this.clipboardAction.destroy(); this.clipboardAction = null; } } }], [{ key: 'isSupported', value: function isSupported() { var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; var actions = typeof action === 'string' ? [action] : action; var support = !!document.queryCommandSupported; actions.forEach(function (action) { support = support && !!document.queryCommandSupported(action); }); return support; } }]); return Clipboard; }(tiny_emitter_default.a); /** * Helper function to retrieve attribute value. * @param {String} suffix * @param {Element} element */ function getAttributeValue(suffix, element) { var attribute = 'data-clipboard-' + suffix; if (!element.hasAttribute(attribute)) { return; } return element.getAttribute(attribute); } /* harmony default export */ var clipboard = __webpack_exports__["default"] = (clipboard_Clipboard); /***/ }) /******/ ])["default"]; }); </script> <style> .listingblock:hover .clipboard { display: block; } .clipboard { display: none; border: 0; font-size: .75em; text-transform: uppercase; font-weight: 500; padding: 6px; color: #999; position: absolute; top: .425rem; right: .5rem; background: transparent; } code + .clipboard { top: -0.05rem !important; right: 3rem !important; } .clipboard:hover, .clipboard:focus, .clipboard:active { outline: 0; background-color: #eee9e6; } </style> <script> $(function() { var pre = document.getElementsByTagName('pre'); for (var i = 0; i < pre.length; i++) { var b = document.createElement('input'); b.setAttribute('role', 'button'); b.setAttribute('type', 'button'); b.value = 'Copy'; b.className = 'clipboard'; if (pre[i].childNodes.length === 1 && pre[i].childNodes[0].nodeType === 3) { var div = document.createElement('div'); div.textContent = pre[i].textContent; pre[i].textContent = ''; pre[i].appendChild(div); } pre[i].appendChild(b); } new ClipboardJS('.clipboard', { text: function(b) { return b.parentNode.innerText; } }).on('success', function(e) { e.clearSelection(); e.trigger.value = 'Copied'; setTimeout(function() { e.trigger.value = 'Copy'; }, 2000); }); }); </script> <style> .hidden { display: none; } .switch { border-width: 1px 1px 0 1px; border-style: solid; border-color: #7a2518; display: inline-block; } .switch--item { padding: 10px; background-color: #ffffff; color: #7a2518; display: inline-block; cursor: pointer; } .switch--item.selected { background-color: #7a2519; color: #ffffff; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script> <script type="text/javascript"> function addBlockSwitches() { $('.primary').each(function() { primary = $(this); createSwitchItem(primary, createBlockSwitch(primary)).item.addClass("selected"); primary.children('.title').remove(); }); $('.secondary').each(function(idx, node) { secondary = $(node); primary = findPrimary(secondary); switchItem = createSwitchItem(secondary, primary.children('.switch')); switchItem.content.addClass('hidden'); findPrimary(secondary).append(switchItem.content); secondary.remove(); }); } function createBlockSwitch(primary) { blockSwitch = $('<div class="switch"></div>'); primary.prepend(blockSwitch); return blockSwitch; } function findPrimary(secondary) { candidate = secondary.prev(); while (!candidate.is('.primary')) { candidate = candidate.prev(); } return candidate; } function createSwitchItem(block, blockSwitch) { blockName = block.children('.title').text(); content = block.children('.content').first().append(block.next('.colist')); item = $('<div class="switch--item">' + blockName + '</div>'); item.on('click', '', content, function(e) { $(this).addClass('selected'); $(this).siblings().removeClass('selected'); e.data.siblings('.content').addClass('hidden'); e.data.removeClass('hidden'); }); blockSwitch.append(item); return {'item': item, 'content': content}; } $(addBlockSwitches); </script> </head> <body class="article toc2 toc-left"> <div id="header"> <h1>Autocomplete for Java Command Line Applications</h1> <div class="details"> <span id="revnumber">version 4.6.1,</span> <span id="revdate">2021-01-03</span> </div> <div id="toc" class="toc2"> <div id="toctitle">Table of Contents</div> <ul class="sectlevel1"> <li><a href="#_command_line_completion">1. Command Line Completion</a></li> <li><a href="#_quick_start_tutorial">2. Quick Start Tutorial</a> <ul class="sectlevel2"> <li><a href="#_create_command">2.1. Create Command</a></li> <li><a href="#_generate_completion_script">2.2. Generate Completion Script</a></li> <li><a href="#_install_completion_script">2.3. Install Completion Script</a></li> <li><a href="#_permanent_installation">2.4. Permanent Installation</a></li> <li><a href="#_distribution">2.5. Distribution</a></li> </ul> </li> <li><a href="#_designing_for_completion">3. Designing for Completion</a> <ul class="sectlevel2"> <li><a href="#_register_subcommands_declaratively">3.1. Register Subcommands Declaratively</a></li> <li><a href="#_use_strong_typing">3.2. Use Strong Typing</a> <ul class="sectlevel3"> <li><a href="#_files_and_directories">3.2.1. Files and Directories</a></li> <li><a href="#_host_names">3.2.2. Host Names</a></li> <li><a href="#_java_enum_values">3.2.3. Java <code>enum</code> Values</a></li> </ul> </li> <li><a href="#_other_completion_candidates">3.3. Other Completion Candidates</a></li> </ul> </li> <li><a href="#_alternative_ways_to_define_commands">4. Alternative Ways to Define Commands</a> <ul class="sectlevel2"> <li><a href="#_alias">4.1. Alias</a></li> <li><a href="#_function">4.2. Function</a></li> <li><a href="#_script">4.3. Script</a></li> </ul> </li> <li><a href="#_completion_script_generation_details">5. Completion Script Generation Details</a> <ul class="sectlevel2"> <li><a href="#_running_autocomplete">5.1. Running AutoComplete</a></li> <li><a href="#_command_name">5.2. Command Name</a></li> <li><a href="#_subcommands">5.3. Subcommands</a></li> <li><a href="#_programmatically_registered_subcommands">5.4. Programmatically Registered Subcommands</a></li> </ul> </li> <li><a href="#_installing_completion_scripts_permanently_in_bashzsh">6. Installing Completion Scripts Permanently in Bash/ZSH</a> <ul class="sectlevel2"> <li><a href="#_zsh">6.1. ZSH</a></li> <li><a href="#_if_bash_completion_is_installed">6.2. If <code>bash-completion</code> is Installed</a></li> <li><a href="#_without_bash_completion_installed">6.3. Without <code>bash-completion</code> Installed</a></li> </ul> </li> <li><a href="#_generating_completion_scripts_during_the_build">7. Generating Completion Scripts During the Build</a> <ul class="sectlevel2"> <li><a href="#_maven_example">7.1. Maven Example</a></li> </ul> </li> <li><a href="#_picocli_user_manual">8. Picocli User Manual</a></li> <li><a href="#_github_project">9. GitHub Project</a></li> <li><a href="#_issue_tracker">10. Issue Tracker</a></li> <li><a href="#_license">11. License</a></li> <li><a href="#_releases">12. Releases</a></li> </ul> </div> </div> <div id="content"> <div id="preamble"> <div class="sectionbody"> <div class="imageblock right"> <div class="content"> <a class="image" href="https://github.com/remkop/picocli"><img src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub"></a> </div> </div> <div class="quoteblock"> <blockquote> Every main method deserves picocli! </blockquote> </div> </div> </div> <div class="sect1"> <h2 id="_command_line_completion">1. Command Line Completion</h2> <div class="sectionbody"> <div class="paragraph"> <p>Starting from version 1.0.0, picocli-based applications can have command line completion in Bash or ZSH Unix shells. Picocli can generate an autocompletion script tailored to your application.</p> </div> <div class="paragraph"> <p>With this script installed, users can type the first few letters of a subcommand or an option, then press the TAB key, and the Unix shell will complete the subcommand or option.</p> </div> <div class="paragraph"> <p>In the case of multiple possible completions, the Unix shell will display all subcommands or options beginning with those few characters. The user can type more characters and press TAB again to see a new, narrowed-down list if the typed characters are still ambiguous, or else complete the subcommand or option.</p> </div> <div class="paragraph"> <p><span class="image"><img src="images/picocli-autocompletion-demo.gif" alt="Autocompletion demo animation"></span></p> </div> </div> </div> <div class="sect1"> <h2 id="_quick_start_tutorial">2. Quick Start Tutorial</h2> <div class="sectionbody"> <div class="paragraph"> <p>This tutorial uses the <a href="index.html#CheckSum-application">CheckSum example application</a> from the picocli user manual. We created a class <code>com.myproject.CheckSum</code> and put it in a jar file, <code>myproject.jar</code>.</p> </div> <div class="paragraph"> <p>Follow these steps to give this application command line autocompletion.</p> </div> <div class="sect2"> <h3 id="_create_command">2.1. Create Command</h3> <div class="paragraph"> <p>First, create an executable command that runs the main application class. For this tutorial, the command name is <code>jchecksum</code>.</p> </div> <div class="paragraph"> <p>We use an <a href="https://en.wikipedia.org/wiki/Alias_(command)">alias</a> here to create the command (see <a href="#_alternative_ways_to_define_commands">alternatives</a>):</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">alias jchecksum='java -cp "picocli-1.0.0.jar;myproject.jar" com.myproject.CheckSum'</code></pre> </div> </div> <div class="paragraph"> <p>Let’s test that the command works:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ jchecksum --help Usage: jchecksum [-h] [-a=<algorithm>] <file> Prints the checksum (MD5 by default) of a file to STDOUT. file The file whose checksum to calculate. -a, --algorithm=<algorithm> MD5, SHA-1, SHA-256, ... -h, --help Show this help message and exit.</code></pre> </div> </div> </div> <div class="sect2"> <h3 id="_generate_completion_script">2.2. Generate Completion Script</h3> <div class="paragraph"> <p>To generate the completion script, run the <code>picocli.AutoComplete</code> class as a java application. Pass it the command name and the fully qualified class name of the annotated command class. (See also <a href="#_completion_script_generation_details">full description</a> for using <code>AutoComplete</code>.)</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">java -cp "picocli-1.0.0.jar;myproject.jar" picocli.AutoComplete -n jchecksum com.myproject.CheckSum</code></pre> </div> </div> <div class="paragraph"> <p>This generates a <code>jchecksum_completion</code> script in the current directory. To verify:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ ls jchecksum_completion myproject.jar picocli-1.0.0.jar</code></pre> </div> </div> </div> <div class="sect2"> <h3 id="_install_completion_script">2.3. Install Completion Script</h3> <div class="paragraph"> <p>Finally, <a href="http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x237.html">source</a> the completion script:</p> </div> <div class="listingblock"> <div class="title">Bash or ZSH</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">. jchecksum_completion</code></pre> </div> </div> <div class="paragraph"> <p>…​and you are done. The <code>jchecksum</code> command now has autocompletion:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ jchecksum <TAB><TAB> -a --algorithm -h --help</code></pre> </div> </div> </div> <div class="sect2"> <h3 id="_permanent_installation">2.4. Permanent Installation</h3> <div class="paragraph"> <p>The above will last for the duration of your shell session. If you want to make this permanent you need to modify your ~/.bashrc or ~/.zshrc file to add a line that defines the command alias and a line that sources the completion script:</p> </div> <div class="listingblock"> <div class="title">Bash</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">echo "alias jchecksum='java -cp \"picocli-1.0.0.jar;myproject.jar\" com.myproject.CheckSum'" >> ~/.bashrc echo ". jchecksum_completion" >> ~/.bashrc</code></pre> </div> </div> <div class="paragraph"> <p>Make sure to use <code>>></code> (append), using a single <code>></code> would overwrite the file.</p> </div> <div class="paragraph"> <p><code>~/.bashrc</code> indicates <code>.bashrc</code> is in your home directory.</p> </div> <div class="paragraph"> <p>(See <a href="#_installing_completion_scripts_permanently_in_bashzsh">Installing Completion Scripts Permanently in Bash/ZSH</a>.)</p> </div> </div> <div class="sect2"> <h3 id="_distribution">2.5. Distribution</h3> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> Have a subcommand that generates a completion script. </td> </tr> </table> </div> <div class="paragraph"> <p>You could generate completion scripts for your commands <a href="#_generating_completion_scripts_during_the_build">during the build</a> and distribute them with your application, but an alternative is to give your application the ability to generate its own completion script on demand.</p> </div> <div class="paragraph"> <p>That allows end users to install completion for your application with a single command. For example, if your utility is called <code>mycommand</code>, users can install completion for it by running the following command:</p> </div> <div class="listingblock"> <div class="title">Bash</div> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ source <(mycommand generate-completion)</code></pre> </div> </div> <div class="paragraph"> <p>This can be accomplished by registering the built-in <code>picocli.AutoComplete.GenerateCompletion</code> class as a subcommand of the top-level command.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">import</span> <span class="include">picocli.AutoComplete.GenerateCompletion</span>; <span class="keyword">import</span> <span class="include">picocli.CommandLine</span>; <span class="keyword">import</span> <span class="include">picocli.CommandLine.Command</span>; <span class="annotation">@Command</span>(name = <span class="string"><span class="delimiter">"</span><span class="content">mycommand</span><span class="delimiter">"</span></span>, subcommands = GenerateCompletion.class) <span class="directive">public</span> <span class="type">class</span> <span class="class">MyApp</span> <span class="directive">implements</span> <span class="predefined-type">Runnable</span> { <span class="annotation">@Override</span> <span class="directive">public</span> <span class="type">void</span> run() { <span class="comment">// top-level command business logic here</span> } <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> args) { <span class="keyword">new</span> CommandLine(<span class="keyword">new</span> MyApp()).execute(args); } }</code></pre> </div> </div> <div class="paragraph"> <p>By default, the <code>generate-completion</code> command shows up as a subcommand in the usage help message of its parent command. Applications that want the completion subcommand to be hidden in the usage help message, can do the following:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span>... args) { CommandLine cmd = <span class="keyword">new</span> CommandLine(<span class="keyword">new</span> MyApp()); CommandLine gen = cmd.getSubcommands().get(<span class="string"><span class="delimiter">"</span><span class="content">generate-completion</span><span class="delimiter">"</span></span>); gen.getCommandSpec().usageMessage().hidden(<span class="predefined-constant">true</span>); <span class="type">int</span> exitCode = cmd.execute(args); <span class="comment">// ...</span> }</code></pre> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_designing_for_completion">3. Designing for Completion</h2> <div class="sectionbody"> <div class="paragraph"> <p>When writing a <a href="index.html">picocli</a>-based command line application there are a few things to consider to facilitate autocompletion.</p> </div> <div class="sect2"> <h3 id="_register_subcommands_declaratively">3.1. Register Subcommands Declaratively</h3> <div class="paragraph"> <p>Register subcommands <a href="index.html#_registering_subcommands_declaratively">declaratively</a> in your application with <code>@Command(subcommands = { …​ })</code> annotations where possible.</p> </div> <div class="paragraph"> <p>This way, you can generate a completion script by passing a single command class name to <code>picocli.AutoComplete</code>, and picocli will be able to infer the full hierarchy of command and subcommands from that top-level command class.</p> </div> <div class="paragraph"> <p>If your application registers subcommands programmatically, you can still generate a completion script, it is just <a href="#_programmatically_registered_subcommands">more work</a>.</p> </div> </div> <div class="sect2"> <h3 id="_use_strong_typing">3.2. Use Strong Typing</h3> <div class="paragraph"> <p>When generating the completion script, picocli inspects the type of the fields annotated with <code>@Option</code>. For some types, tab completion can also generate possible option <em>values</em>.</p> </div> <div class="paragraph"> <p>Picocli can generate completion matches for the following types:</p> </div> <div class="ulist"> <ul> <li> <p><code>java.io.File</code></p> </li> <li> <p><code>java.nio.file.Path</code></p> </li> <li> <p><code>java.net.InetAddress</code></p> </li> <li> <p>any java <code>enum</code></p> </li> </ul> </div> <div class="sect3"> <h4 id="_files_and_directories">3.2.1. Files and Directories</h4> <div class="paragraph"> <p>Generating autocomplete matches for <code>@Option</code> fields of type <code>java.io.File</code> or <code>java.nio.file.Path</code> will display a list of all files and directories in the current directory.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ demo --file <TAB><TAB> basic.bash hierarchy nestedSubcommands.bash</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_host_names">3.2.2. Host Names</h4> <div class="paragraph"> <p>Generating autocomplete matches for <code>@Option</code> fields of type <code>java.net.InetAddress</code> will display a list of known hosts (from your <code>/etc/hosts</code> file).</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ demo --host <TAB><TAB> cluster-p-1 openvpn-client.myvpn.picocli.com cluster-p-2 picop1 cluster-p-3 picop2 cluster-p-4 picop3 cluster-scm-1 picop4 client.openvpn.net picoscm1</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_java_enum_values">3.2.3. Java <code>enum</code> Values</h4> <div class="paragraph"> <p>Generating autocomplete matches for <code>@Option</code> fields of any Java <code>enum</code> type will display the list of enum values.</p> </div> <div class="paragraph"> <p>For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ demo --timeUnit <TAB><TAB> DAYS HOURS MICROSECONDS MILLISECONDS MINUTES NANOSECONDS SECONDS</code></pre> </div> </div> </div> </div> <div class="sect2"> <h3 id="_other_completion_candidates">3.3. Other Completion Candidates</h3> <div class="paragraph"> <p>Picocli 3.2 introduces a <code>completionCandidates</code> API that can be used to generate completion candidates regardless of the type of the option or positional parameter.</p> </div> <div class="paragraph"> <p>Picocli calls this iterator when the completion script is generated.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="_alternative_ways_to_define_commands">4. Alternative Ways to Define Commands</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section describes creating commands in more depth than the <a href="#_quick_start_tutorial">Quick Start Tutorial</a>.</p> </div> <div class="paragraph"> <p>In Bash and ZSH, there are multiple ways to create an executable command for a java class.</p> </div> <div class="sect2"> <h3 id="_alias">4.1. Alias</h3> <div class="paragraph"> <p>One way is to define an alias:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">alias jchecksum='java -cp "picocli-1.0.0.jar;myproject.jar" com.myproject.CheckSum'</code></pre> </div> </div> <div class="paragraph"> <p>Be aware that the alias only lasts as long as the current shell session. To make it permanent, add it to your <code>~/.bashrc</code> or <code>~/.zshrc</code> file.</p> </div> <div class="paragraph"> <p>You may also want to specify the full path to the jar files in the classpath so that the command can be executed anywhere.</p> </div> </div> <div class="sect2"> <h3 id="_function">4.2. Function</h3> <div class="paragraph"> <p>Another way is to define a function:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">jchecksum() { java -cp "picocli-1.0.0.jar;myproject.jar" com.myproject.CheckSum "$@" }</code></pre> </div> </div> <div class="paragraph"> <p>To make it permanent, add it to your <code>~/.bashrc</code> or <code>~/.zshrc</code> file.</p> </div> </div> <div class="sect2"> <h3 id="_script">4.3. Script</h3> <div class="paragraph"> <p>Yet another way is to create a script:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ echo '#!/usr/bin/env bash' > jchecksum $ echo 'java -cp "picocli-1.0.0.jar;myproject.jar" com.myproject.CheckSum $@' >> jchecksum $ chmod 755 jchecksum $ cat jchecksum #!/usr/bin/env bash java -cp "picocli-1.0.0.jar;myproject.jar" com.myproject.CheckSum $@</code></pre> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_completion_script_generation_details">5. Completion Script Generation Details</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section describes generating completion scripts in more depth than the <a href="#_quick_start_tutorial">Quick Start Tutorial</a>.</p> </div> <div class="sect2"> <h3 id="_running_autocomplete">5.1. Running AutoComplete</h3> <div class="paragraph"> <p>To generate the completion script, run the <code>picocli.AutoComplete</code> class as a java application, passing it the fully qualified class name of the annotated command object.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ java -cp "picocli-1.0.0.jar;myproject.jar" picocli.AutoComplete com.myproject.CheckSum</code></pre> </div> </div> <div class="paragraph"> <p>This will instantiate your command, and inspect it for <a href="http://picocli.info/apidocs/picocli/CommandLine.Option.html"><code>@Option</code></a> and <a href="http://picocli.info/apidocs/picocli/CommandLine.Command.html"><code>@Command</code></a> annotations. Based on these annotations it will generate a completion script in the current directory.</p> </div> <div class="paragraph"> <p>Because of this, the command class needs to be on the classpath when running the <code>picocli.AutoComplete</code> class.</p> </div> </div> <div class="sect2"> <h3 id="_command_name">5.2. Command Name</h3> <div class="paragraph"> <p>The name of the generated completion script is based on the <code>@Command(name ="<COMMAND-NAME>")</code> <a href="index.html#_command_name">annotation</a>, or, if that is missing, the command class name. Use the <code>-n</code> or <code>--name</code> option to control the name of the command that the completion script is for.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">$ java -cp "picocli-1.0.0.jar;myproject.jar" picocli.AutoComplete -n jchecksum com.myproject.CheckSum</code></pre> </div> </div> <div class="paragraph"> <p>This will generate a <code>jchecksum_completion</code> script in the current directory.</p> </div> <div class="paragraph"> <p>Other options are:</p> </div> <div class="ulist"> <ul> <li> <p>Use <code>-o</code> or <code>--completionScript</code> to specify the full path to the completion script to generate.</p> </li> <li> <p>Use the <code>-f</code> or <code>--force</code> option to overwrite existing files.</p> </li> <li> <p>Use the <code>-w</code>, <code>--writeCommandScript</code> option to generate a sample command script.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="_subcommands">5.3. Subcommands</h3> <div class="paragraph"> <p>For commands with subcommands, bear in mind that the class that generates the completion script (<code>picocli.AutoComplete</code>) needs the full hierarchy of command and subcommands to generate a completion script that also works for the subcommands.</p> </div> <div class="paragraph"> <p>The above will work when subcommands are registered declaratively with annotations like <code>@Command(subcommands = { …​ })</code>.</p> </div> </div> <div class="sect2"> <h3 id="_programmatically_registered_subcommands">5.4. Programmatically Registered Subcommands</h3> <div class="paragraph"> <p>When subcommands are not registered declaratively, you need to do a bit more work. You need to create a small program that does the following:</p> </div> <div class="ulist"> <ul> <li> <p>Create a <code>CommandLine</code> instance with the full hierarchy of nested subcommands.</p> </li> </ul> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// programmatically (see above for declarative example)</span> CommandLine hierarchy = <span class="keyword">new</span> CommandLine(<span class="keyword">new</span> TopLevel()) .addSubcommand(<span class="string"><span class="delimiter">"</span><span class="content">sub1</span><span class="delimiter">"</span></span>, <span class="keyword">new</span> Subcommand1()) .addSubcommand(<span class="string"><span class="delimiter">"</span><span class="content">sub2</span><span class="delimiter">"</span></span>, <span class="keyword">new</span> Subcommand2());</code></pre> </div> </div> <div class="ulist"> <ul> <li> <p>Pass this <code>CommandLine</code> instance and the name of the script to the <code>picocli.AutoComplete::bash</code> method. The method will return the source code of a completion script. Save the source code to a file and install it.</p> </li> </ul> </div> </div> </div> </div> <div class="sect1"> <h2 id="_installing_completion_scripts_permanently_in_bashzsh">6. Installing Completion Scripts Permanently in Bash/ZSH</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section describes installing completion scripts in more depth than the <a href="#_quick_start_tutorial">Quick Start Tutorial</a>.</p> </div> <div class="paragraph"> <p><a href="http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x237.html">Source</a> the generated completion script to install it in your current bash or zsh session.</p> </div> <div class="sect2"> <h3 id="_zsh">6.1. ZSH</h3> <div class="paragraph"> <p>Zsh can handle bash completions functions. The latest development version of zsh has a function <code>bashcompinit</code>, that when run will allow zsh to read bash completion specifications and functions. The zshcompsys man page has details.</p> </div> <div class="paragraph"> <p>Since picocli 4.1, the generated completion script contains the following code to run <code>bashcompinit</code> after <code>compinit</code>; this will define <code>complete</code> and <code>compgen</code> functions corresponding to the bash builtins. It is no longer necessary to manually run the below commands.</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">autoload -U +X compinit && compinit autoload -U +X bashcompinit && bashcompinit</code></pre> </div> </div> </div> <div class="sect2"> <h3 id="_if_bash_completion_is_installed">6.2. If <a href="https://github.com/scop/bash-completion"><code>bash-completion</code></a> is Installed</h3> <div class="paragraph"> <p>To install it more permanently, place the completion script file in <code>/etc/bash_completion.d</code> (or <code>/usr/local/etc/bash_completion.d</code> on a Mac). If <code>bash-completion</code> is installed, placing the completion script in either of these directories should be sufficient. (Source your <code>~/.bash_profile</code> or launch a new terminal to start using this completion script.)</p> </div> </div> <div class="sect2"> <h3 id="_without_bash_completion_installed">6.3. Without <code>bash-completion</code> Installed</h3> <div class="paragraph"> <p>Alternatively, make a directory <code>mkdir ~/bash_completion.d</code>, and place the completion script in this directory. Edit your <code>~/.bashrc</code> file (or <code>~/.zshrc</code> file on ZSH) and add the following:</p> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="bash">for bcfile in ~/bash_completion.d/* ; do . $bcfile done</code></pre> </div> </div> <div class="paragraph"> <p>All completion scripts in the <code>~/bash_completion.d</code> directory will now be available every time you launch a new shell.</p> </div> <div class="paragraph"> <p>Source the generated completion script or launch a new terminal to start using this completion script.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="_generating_completion_scripts_during_the_build">7. Generating Completion Scripts During the Build</h2> <div class="sectionbody"> <div class="paragraph"> <p>It may be useful to generate your completion scripts automatically during the build. Below is an example Maven snippet that demonstrates how to achieve this.</p> </div> <div class="sect2"> <h3 id="_maven_example">7.1. Maven Example</h3> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> Setting system property <code>picocli.autocomplete.systemExitOnError</code> ensures the build fails if there is any problem generating the completion script (requires picocli v3.9.1). </td> </tr> </table> </div> <div class="listingblock"> <div class="content"> <pre class="CodeRay highlight"><code data-lang="xml"><span class="tag"><plugin></span> <span class="tag"><groupId></span>org.codehaus.mojo<span class="tag"></groupId></span> <span class="tag"><artifactId></span>exec-maven-plugin<span class="tag"></artifactId></span> <span class="tag"><version></span>${exec-maven-plugin.version}<span class="tag"></version></span> <span class="tag"><executions></span> <span class="tag"><execution></span> <span class="tag"><id></span>generate-autocompletion-script<span class="tag"></id></span> <span class="tag"><phase></span>package<span class="tag"></phase></span> <span class="tag"><goals></span> <span class="tag"><goal></span>exec<span class="tag"></goal></span> <span class="tag"></goals></span> <span class="tag"></execution></span> <span class="tag"></executions></span> <span class="tag"><configuration></span> <span class="tag"><executable></span>java<span class="tag"></executable></span> <span class="tag"><arguments></span> <span class="tag"><argument></span>-Dpicocli.autocomplete.systemExitOnError<span class="tag"></argument></span> <span class="tag"><argument></span>-cp<span class="tag"></argument></span> <span class="tag"><classpath</span><span class="tag">/></span> <span class="tag"><argument></span>picocli.AutoComplete<span class="tag"></argument></span> <span class="tag"><argument></span>--force<span class="tag"></argument></span><span class="comment"><!-- overwrite if exists --></span> <span class="tag"><argument></span>--completionScript<span class="tag"></argument></span> <span class="tag"><argument></span>${project.build.directory}/mycommand_completion.sh<span class="tag"></argument></span> <span class="tag"><argument></span>mypackage.MyCommand<span class="tag"></argument></span><span class="comment"><!-- replace with your class --></span> <span class="tag"></arguments></span> <span class="tag"></configuration></span> <span class="tag"></plugin></span></code></pre> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_picocli_user_manual">8. Picocli User Manual</h2> <div class="sectionbody"> <div class="paragraph"> <p>The <a href="index.html">picocli user manual</a> explains how to build Java command line applications with picocli.</p> </div> </div> </div> <div class="sect1"> <h2 id="_github_project">9. GitHub Project</h2> <div class="sectionbody"> <div class="paragraph"> <p>The <a href="https://github.com/remkop/picocli">GitHub project</a> has the source code, tests, build scripts, etc.</p> </div> <div class="paragraph"> <p>Star <span class="icon"><i class="fa fa-star-o"></i></span> or fork <span class="icon"><i class="fa fa-code-fork"></i></span> this project on GitHub if you like it! (Projects with many <span class="icon"><i class="fa fa-code-fork"></i></span> forks are easier to find on GitHub Search.)</p> </div> </div> </div> <div class="sect1"> <h2 id="_issue_tracker">10. Issue Tracker</h2> <div class="sectionbody"> <div class="paragraph"> <p>Please use the <a href="https://github.com/remkop/picocli/issues">Issue Tracker</a> to report bugs or request features.</p> </div> </div> </div> <div class="sect1"> <h2 id="_license">11. License</h2> <div class="sectionbody"> <div class="paragraph"> <p>Picocli is licensed under the <a href="https://github.com/remkop/picocli/blob/master/LICENSE">Apache License 2.0</a>.</p> </div> </div> </div> <div class="sect1"> <h2 id="_releases">12. Releases</h2> <div class="sectionbody"> <div class="paragraph"> <p>Previous versions are available from the GitHub project <a href="https://github.com/remkop/picocli/releases">Releases</a>.</p> </div> </div> </div> </div> <div id="footer"> <div id="footer-text"> Version 4.6.1<br> Last updated 2021-01-03 11:47:21 +0900 </div> </div> </body> </html>