From 7090e9b805a32b8a9d9785adca6ccd96872c88f3 Mon Sep 17 00:00:00 2001 From: Sasha Fedchin Date: Mon, 29 Jul 2024 11:31:57 +0200 Subject: [PATCH] Use piccoli instead of apache cli --- .github/workflows/exampleExpectedResult.tsv | 93 +- .github/workflows/main.yml | 13 +- README.md | 101 +- acrostics.iml | 1 - ...n_acrostics-identification-task-dataset.sh | 8 +- lib/commons-cli-1.5.0.jar | Bin 58284 -> 0 bytes src/acrostics/CLO.java | 176 +- src/acrostics/CommandLine.java | 19240 ++++++++++++++++ src/acrostics/Main.java | 6 +- 9 files changed, 19396 insertions(+), 242 deletions(-) delete mode 100644 lib/commons-cli-1.5.0.jar create mode 100644 src/acrostics/CommandLine.java diff --git a/.github/workflows/exampleExpectedResult.tsv b/.github/workflows/exampleExpectedResult.tsv index e537c39..3cfee54 100644 --- a/.github/workflows/exampleExpectedResult.tsv +++ b/.github/workflows/exampleExpectedResult.tsv @@ -1,47 +1,48 @@ file,acrostic,rank -data/example/The PearlVolume 18Acrostic - Madrigal.txt prick▁fuck 2401.8522 -data/example/Flint and Feather (1914)Part 3Brandon.txt brandon 2867.4580 -data/example/The Canadian soldiers' song book.djvu57.txt mother 3222.5353 -data/example/Devon and Cornwall Notes and Queries.djvu21.txt thomas 4883.2451 -data/example/The Chronicles of CooperstownChapter IV.txt waanna▁cooper 5883.3502 -data/example/Notes and Queries - Series 12 - Volume 4.djvu257.txt mary▁stokes 10552.669 -data/example/Whole prophecies of Scotland, England, Ireland, France, and Denmark (1).pdf46.txt of▁god▁the 26156.512 -data/example/Through the Looking-Glass, and What Alice Found There.djvu243.txt alice▁pleas▁and 55706.981 -data/example/The Elements of LawPart IChapter 1.txt thomas▁of 107412.96 -data/example/Archaeological Journal, Volume 29.djvu98.txt the▁us▁parker 155277.74 -data/example/Love's trilogy.djvu79.txt perhaps 214055.82 -data/example/Amazing Stories Volume 17 Number 06.djvu6.txt amazing 649765.01 -data/example/Life and wonderful prophecies of Donald Cargill (1).pdf24.txt master▁donald 702177.78 -data/example/Life and wonderful prophecies of Donald Cargill (2).pdf24.txt master▁donald 702177.78 -data/example/Sentimental valentine writer.pdf11.txt william 1135223.6 -data/example/New mirror of love.pdf24.txt william 1135223.6 -data/example/United States Army Field Manual 7-93 Long-Range Surveillance Unit OperationsAppendix F.txt survival 2148141.6 -data/example/Collingwood - Life and Letters of Lewis Carroll.djvu388.txt agnes▁georgina▁hull 2387092.0 -data/example/Clouds without Water (Crowley, 1909).djvu24.txt kathleen▁bruce 2876832.1 -data/example/New mirror of love.pdf19.txt love▁you▁henry 2937325.2 -data/example/Notes and Queries - Series 2 - Volume 1.djvu216.txt william▁bed▁low 3897305.8 -data/example/The Confessions of William-Henry Ireland.txt tail▁chaucer▁fa▁pali▁at▁chatterton 4181925.7 -data/example/Carroll - Rhyme and Reason.djvu11.txt gertrude▁chat▁away 5071868.8 -data/example/The Hunting of the Snark (1876).djvu11.txt gertrude▁chat▁away 5071868.8 -data/example/Ben King's VerseAsphodel.txt cornelia▁bassett 5531929.3 -data/example/Carroll - Three Sunsets.djvu83.txt prince▁charlie 6845483.7 -data/example/Elegy upon the death of that famous and faithful minister and martyr Mr. James Renwick.pdf11.txt master▁james 9902015.3 -data/example/The Alchemist (Jonson)Argument.txt the▁alchemist 10758822 -data/example/The Works of Ben Jonson - Gifford - Volume 4.djvu13.txt the▁alchemist 10758822 -data/example/Christian Astrology.txt william▁lilly 22242993 -data/example/Notes and Queries - Series 9 - Volume 2.djvu394.txt charles▁franck 22864223 -data/example/Whole prophecies of Scotland, England, Ireland, France & Denmark.pdf46.txt christ▁sonne▁of▁god▁the 51340131 -data/example/Most remarkable passages in the life of the honourable Colonel James Gardiner.pdf24.txt james▁gardiner 1.2367865E+8 -data/example/An Acrostic.txt elizabeth 3.2083606E+8 -data/example/Through the looking-glass and what Alice found there (IA throughlookinggl00carr4).pdf323.txt alice▁pleasance▁liddell 4.4088332E+8 -data/example/Complete Works of Lewis Carroll.djvu292.txt alice▁pleasance▁liddell 4.4088332E+8 -data/example/Notes by the Way.djvu61.txt to▁joseph▁knight 1.9729025E+9 -data/example/This Canada of ours and other poems.djvu39.txt as▁the▁great▁divided 1.6046686E+10 -data/example/The complete poetical works and letters of John Keats, 1899.djvu279.txt georgiana▁augusta▁keats 4.9096952E+10 -data/example/Good news to Scotland (2).pdf2.txt master▁richard▁cameron 2.4322116E+11 -data/example/Good news to Scotland (1).pdf2.txt master▁richard▁cameron 2.4322116E+11 -data/example/St. Nicholas - Volume 41, Part 1.djvu59.txt thanksgiving 3.0636700E+11 -data/example/The PearlVolume 18Acrostic.txt is▁sweet▁when▁young▁and▁tender 1.8799826E+12 -data/example/Elizabeth (Poe).txt elizabeth▁rebecca 2.2742451E+12 -data/example/The Old GuardVolume 1Issue 1Acrostic.txt george▁washington 2.8634869E+12 -data/example/The Confessions of William-Henry Ireland.txt warwick▁at▁dudley▁at▁southampton▁at▁rivers▁at▁shakspeare 8.8067434E+27 +data/example/Flint and Feather (1914)Part 3Canada.txt canada 1053.8960 +data/example/The PearlVolume 18Acrostic - The Martyr.txt fuck▁my▁cunt▁dear▁papa 2536.9493 +data/example/Flint and Feather (1914)Part 3Brandon.txt brandon 3092.9519 +data/example/The Canadian soldiers' song book.djvu57.txt mother 3164.0043 +data/example/Devon and Cornwall Notes and Queries.djvu21.txt thomas 4477.4781 +data/example/Notes and Queries - Series 12 - Volume 4.djvu257.txt mary▁stokes 13933.539 +data/example/The PearlVolume 18Acrostic - Madrigal.txt cunt▁prick▁fuck 14796.506 +data/example/Whole prophecies of Scotland, England, Ireland, France, and Denmark (1).pdf46.txt sonne▁of▁god▁the 23421.687 +data/example/Through the Looking-Glass, and What Alice Found There.djvu243.txt alice▁pleas▁and 65249.310 +data/example/The Elements of LawPart IChapter 1.txt thomas▁of 100742.81 +data/example/Archaeological Journal, Volume 29.djvu98.txt the▁us▁parker 205516.31 +data/example/Love's trilogy.djvu79.txt perhaps 239268.61 +data/example/Life and wonderful prophecies of Donald Cargill (1).pdf24.txt master▁donald 550373.21 +data/example/Life and wonderful prophecies of Donald Cargill (2).pdf24.txt master▁donald 550373.21 +data/example/Amazing Stories Volume 17 Number 06.djvu6.txt amazing 565896.26 +data/example/Sentimental valentine writer.pdf11.txt william 1024341.2 +data/example/New mirror of love.pdf24.txt william 1024341.2 +data/example/Clouds without Water (Crowley, 1909).djvu24.txt kathleen▁bruce 1414519.3 +data/example/Collingwood - Life and Letters of Lewis Carroll.djvu388.txt agnes▁georgina▁hull 1857954.0 +data/example/United States Army Field Manual 7-93 Long-Range Surveillance Unit OperationsAppendix F.txt survival 1914206.3 +data/example/The Confessions of William-Henry Ireland.txt tail▁chaucer▁fa▁pali▁at▁chatterton 2949134.8 +data/example/New mirror of love.pdf19.txt love▁you▁henry 3346046.1 +data/example/Notes and Queries - Series 2 - Volume 1.djvu216.txt william▁bed▁low 3895124.0 +data/example/Carroll - Rhyme and Reason.djvu11.txt gertrude▁chat▁away 4860150.2 +data/example/The Hunting of the Snark (1876).djvu11.txt gertrude▁chat▁away 4860150.2 +data/example/Elegy upon the death of that famous and faithful minister and martyr Mr. James Renwick.pdf11.txt master▁james 8328207.9 +data/example/The Alchemist (Jonson)Argument.txt the▁alchemist 11557749 +data/example/The Works of Ben Jonson - Gifford - Volume 4.djvu13.txt the▁alchemist 11557749 +data/example/Carroll - Three Sunsets.djvu83.txt prince▁charlie 14336506 +data/example/Christian Astrology.txt william▁lilly 22086068 +data/example/Ben King's VerseAsphodel.txt cornelia▁bassett 22318962 +data/example/Notes and Queries - Series 9 - Volume 2.djvu394.txt charles▁franck 37175627 +data/example/Whole prophecies of Scotland, England, Ireland, France & Denmark.pdf46.txt christ▁sonne▁of▁god▁the 86669560 +data/example/Most remarkable passages in the life of the honourable Colonel James Gardiner.pdf24.txt james▁gardiner 1.2227672E+8 +data/example/An Acrostic.txt elizabeth 3.2799235E+8 +data/example/Through the looking-glass and what Alice found there (IA throughlookinggl00carr4).pdf323.txt alice▁pleasance▁liddell 5.0375007E+8 +data/example/Complete Works of Lewis Carroll.djvu292.txt alice▁pleasance▁liddell 5.0375007E+8 +data/example/Notes by the Way.djvu61.txt to▁joseph▁knight 1.6465724E+9 +data/example/This Canada of ours and other poems.djvu39.txt as▁the▁great▁divided 1.8429494E+10 +data/example/The complete poetical works and letters of John Keats, 1899.djvu279.txt georgiana▁augusta▁keats 4.0955944E+10 +data/example/Good news to Scotland (2).pdf2.txt master▁richard▁cameron 1.6211098E+11 +data/example/Good news to Scotland (1).pdf2.txt master▁richard▁cameron 1.6211098E+11 +data/example/St. Nicholas - Volume 41, Part 1.djvu59.txt thanksgiving 4.1471177E+11 +data/example/Elizabeth (Poe).txt elizabeth▁rebecca 1.6337993E+12 +data/example/The Old GuardVolume 1Issue 1Acrostic.txt george▁washington 3.5446523E+12 +data/example/The PearlVolume 18Acrostic.txt cunt▁is▁sweet▁when▁young▁and▁tender 3.6600743E+12 +data/example/The Confessions of William-Henry Ireland.txt warwick▁at▁dudley▁at▁southampton▁at▁rivers▁at▁shakspeare 7.6181055E+27 \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4f976bf..c082242 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,17 +24,8 @@ jobs: fetch-depth: 0 submodules: true - - name: Compile on Mac or Ubuntu - if: matrix.os != 'windows-latest' - run: | - javac -encoding UTF-8 -cp src:lib/commons-cli-1.5.0.jar src/acrostics/*.java - - - name: Compile on Windows - if: matrix.os == 'windows-latest' - run: | - javac -encoding UTF-8 -cp src:lib/commons-cli-1.5.0.jar src/acrostics/*.java - - name: Test run: | - java -cp src:lib/commons-cli-1.5.0.jar acrostics.Main -input data/example -language EN -mode LINE -charset utf-8 -outputSize 4000 --concise > result.tsv + javac -encoding UTF-8 -cp src src/acrostics/*.java + java -cp src acrostics.Main -input data/example -language EN -mode LINE -charset utf-8 -outputSize 4000 --concise > result.tsv diff -w result.tsv .github/workflows/exampleExpectedResult.tsv \ No newline at end of file diff --git a/README.md b/README.md index 9291003..9ff9cfe 100644 --- a/README.md +++ b/README.md @@ -27,16 +27,16 @@ We have tested AcrosticScout on Mac OS and Linux. First, compile the code from the base directory using: ```bash -javac -encoding UTF-8 -cp src:lib/commons-cli-1.5.0.jar src/acrostics/*.java +javac -cp src -encoding UTF-8 src/acrostics/*.java ``` Then run AcrosticScout using the command below, replacing `INPUT` and `LANG` with the name of the directory that contains the dataset you wish AcrosticScout to analyze and the language of that dataset, respectively: ```bash -java -cp src:lib/commons-cli-1.5.0.jar acrostics.Main -input INPUT -language LANG +java -cp src acrostics.Main -input INPUT -language LANG ``` -AcrosticScout accepts multiple optional command line arguments -- run the tool with the `--help` flag to get the up-to-date list of all available options. +AcrosticScout accepts multiple optional command line arguments (thank you, [picocli](https://github.com/remkop/picocli/tree/v4.7.6)) -- run the tool with the `--help` flag to get the up-to-date list of all available options. ## Hello World example @@ -44,7 +44,7 @@ This repository includes an example dataset comprising a subset of pages with ac You can test AcrosticScout on this small dataset using: ```bash -java -cp src:lib/commons-cli-1.5.0.jar acrostics.Main -input data/example -language EN -mode LINE -charset utf-8 -outputSize 4000 --concise +java -cp src acrostics.Main -input data/example -language EN -mode LINE -charset utf-8 -outputSize 4000 --concise ``` Here is the meaning behind each of the options used: @@ -59,52 +59,53 @@ Specifically, you should be getting the following output (highest ranked acrosti ``` file,acrostic,rank -data/example/The PearlVolume 18Acrostic - Madrigal.txt prick▁fuck 2401.8522 -data/example/Flint and Feather (1914)Part 3Brandon.txt brandon 2867.4580 -data/example/The Canadian soldiers' song book.djvu57.txt mother 3222.5353 -data/example/Devon and Cornwall Notes and Queries.djvu21.txt thomas 4883.2451 -data/example/The Chronicles of CooperstownChapter IV.txt waanna▁cooper 5883.3502 -data/example/Notes and Queries - Series 12 - Volume 4.djvu257.txt mary▁stokes 10552.669 -data/example/Whole prophecies of Scotland, England, Ireland, France, and Denmark (1).pdf46.txt of▁god▁the 26156.512 -data/example/Through the Looking-Glass, and What Alice Found There.djvu243.txt alice▁pleas▁and 55706.981 -data/example/The Elements of LawPart IChapter 1.txt thomas▁of 107412.96 -data/example/Archaeological Journal, Volume 29.djvu98.txt the▁us▁parker 155277.74 -data/example/Love's trilogy.djvu79.txt perhaps 214055.82 -data/example/Amazing Stories Volume 17 Number 06.djvu6.txt amazing 649765.01 -data/example/Life and wonderful prophecies of Donald Cargill (1).pdf24.txt master▁donald 702177.78 -data/example/Life and wonderful prophecies of Donald Cargill (2).pdf24.txt master▁donald 702177.78 -data/example/Sentimental valentine writer.pdf11.txt william 1135223.6 -data/example/New mirror of love.pdf24.txt william 1135223.6 -data/example/United States Army Field Manual 7-93 Long-Range Surveillance Unit OperationsAppendix F.txt survival 2148141.6 -data/example/Collingwood - Life and Letters of Lewis Carroll.djvu388.txt agnes▁georgina▁hull 2387092.0 -data/example/Clouds without Water (Crowley, 1909).djvu24.txt kathleen▁bruce 2876832.1 -data/example/New mirror of love.pdf19.txt love▁you▁henry 2937325.2 -data/example/Notes and Queries - Series 2 - Volume 1.djvu216.txt william▁bed▁low 3897305.8 -data/example/The Confessions of William-Henry Ireland.txt tail▁chaucer▁fa▁pali▁at▁chatterton 4181925.7 -data/example/Carroll - Rhyme and Reason.djvu11.txt gertrude▁chat▁away 5071868.8 -data/example/The Hunting of the Snark (1876).djvu11.txt gertrude▁chat▁away 5071868.8 -data/example/Ben King's VerseAsphodel.txt cornelia▁bassett 5531929.3 -data/example/Carroll - Three Sunsets.djvu83.txt prince▁charlie 6845483.7 -data/example/Elegy upon the death of that famous and faithful minister and martyr Mr. James Renwick.pdf11.txt master▁james 9902015.3 -data/example/The Alchemist (Jonson)Argument.txt the▁alchemist 10758822 -data/example/The Works of Ben Jonson - Gifford - Volume 4.djvu13.txt the▁alchemist 10758822 -data/example/Christian Astrology.txt william▁lilly 22242993 -data/example/Notes and Queries - Series 9 - Volume 2.djvu394.txt charles▁franck 22864223 -data/example/Whole prophecies of Scotland, England, Ireland, France & Denmark.pdf46.txt christ▁sonne▁of▁god▁the 51340131 -data/example/Most remarkable passages in the life of the honourable Colonel James Gardiner.pdf24.txt james▁gardiner 1.2367865E+8 -data/example/An Acrostic.txt elizabeth 3.2083606E+8 -data/example/Through the looking-glass and what Alice found there (IA throughlookinggl00carr4).pdf323.txt alice▁pleasance▁liddell 4.4088332E+8 -data/example/Complete Works of Lewis Carroll.djvu292.txt alice▁pleasance▁liddell 4.4088332E+8 -data/example/Notes by the Way.djvu61.txt to▁joseph▁knight 1.9729025E+9 -data/example/This Canada of ours and other poems.djvu39.txt as▁the▁great▁divided 1.6046686E+10 -data/example/The complete poetical works and letters of John Keats, 1899.djvu279.txt georgiana▁augusta▁keats 4.9096952E+10 -data/example/Good news to Scotland (2).pdf2.txt master▁richard▁cameron 2.4322116E+11 -data/example/Good news to Scotland (1).pdf2.txt master▁richard▁cameron 2.4322116E+11 -data/example/St. Nicholas - Volume 41, Part 1.djvu59.txt thanksgiving 3.0636700E+11 -data/example/The PearlVolume 18Acrostic.txt is▁sweet▁when▁young▁and▁tender 1.8799826E+12 -data/example/Elizabeth (Poe).txt elizabeth▁rebecca 2.2742451E+12 -data/example/The Old GuardVolume 1Issue 1Acrostic.txt george▁washington 2.8634869E+12 -data/example/The Confessions of William-Henry Ireland.txt warwick▁at▁dudley▁at▁southampton▁at▁rivers▁at▁shakspeare 8.8067434E+27 +data/example/Flint and Feather (1914)Part 3Canada.txt canada 1053.8960 +data/example/The PearlVolume 18Acrostic - The Martyr.txt fuck▁my▁cunt▁dear▁papa 2536.9493 +data/example/Flint and Feather (1914)Part 3Brandon.txt brandon 3092.9519 +data/example/The Canadian soldiers' song book.djvu57.txt mother 3164.0043 +data/example/Devon and Cornwall Notes and Queries.djvu21.txt thomas 4477.4781 +data/example/Notes and Queries - Series 12 - Volume 4.djvu257.txt mary▁stokes 13933.539 +data/example/The PearlVolume 18Acrostic - Madrigal.txt cunt▁prick▁fuck 14796.506 +data/example/Whole prophecies of Scotland, England, Ireland, France, and Denmark (1).pdf46.txt sonne▁of▁god▁the 23421.687 +data/example/Through the Looking-Glass, and What Alice Found There.djvu243.txt alice▁pleas▁and 65249.310 +data/example/The Elements of LawPart IChapter 1.txt thomas▁of 100742.81 +data/example/Archaeological Journal, Volume 29.djvu98.txt the▁us▁parker 205516.31 +data/example/Love's trilogy.djvu79.txt perhaps 239268.61 +data/example/Life and wonderful prophecies of Donald Cargill (1).pdf24.txt master▁donald 550373.21 +data/example/Life and wonderful prophecies of Donald Cargill (2).pdf24.txt master▁donald 550373.21 +data/example/Amazing Stories Volume 17 Number 06.djvu6.txt amazing 565896.26 +data/example/Sentimental valentine writer.pdf11.txt william 1024341.2 +data/example/New mirror of love.pdf24.txt william 1024341.2 +data/example/Clouds without Water (Crowley, 1909).djvu24.txt kathleen▁bruce 1414519.3 +data/example/Collingwood - Life and Letters of Lewis Carroll.djvu388.txt agnes▁georgina▁hull 1857954.0 +data/example/United States Army Field Manual 7-93 Long-Range Surveillance Unit OperationsAppendix F.txt survival 1914206.3 +data/example/The Confessions of William-Henry Ireland.txt tail▁chaucer▁fa▁pali▁at▁chatterton 2949134.8 +data/example/New mirror of love.pdf19.txt love▁you▁henry 3346046.1 +data/example/Notes and Queries - Series 2 - Volume 1.djvu216.txt william▁bed▁low 3895124.0 +data/example/Carroll - Rhyme and Reason.djvu11.txt gertrude▁chat▁away 4860150.2 +data/example/The Hunting of the Snark (1876).djvu11.txt gertrude▁chat▁away 4860150.2 +data/example/Elegy upon the death of that famous and faithful minister and martyr Mr. James Renwick.pdf11.txt master▁james 8328207.9 +data/example/The Alchemist (Jonson)Argument.txt the▁alchemist 11557749 +data/example/The Works of Ben Jonson - Gifford - Volume 4.djvu13.txt the▁alchemist 11557749 +data/example/Carroll - Three Sunsets.djvu83.txt prince▁charlie 14336506 +data/example/Christian Astrology.txt william▁lilly 22086068 +data/example/Ben King's VerseAsphodel.txt cornelia▁bassett 22318962 +data/example/Notes and Queries - Series 9 - Volume 2.djvu394.txt charles▁franck 37175627 +data/example/Whole prophecies of Scotland, England, Ireland, France & Denmark.pdf46.txt christ▁sonne▁of▁god▁the 86669560 +data/example/Most remarkable passages in the life of the honourable Colonel James Gardiner.pdf24.txt james▁gardiner 1.2227672E+8 +data/example/An Acrostic.txt elizabeth 3.2799235E+8 +data/example/Through the looking-glass and what Alice found there (IA throughlookinggl00carr4).pdf323.txt alice▁pleasance▁liddell 5.0375007E+8 +data/example/Complete Works of Lewis Carroll.djvu292.txt alice▁pleasance▁liddell 5.0375007E+8 +data/example/Notes by the Way.djvu61.txt to▁joseph▁knight 1.6465724E+9 +data/example/This Canada of ours and other poems.djvu39.txt as▁the▁great▁divided 1.8429494E+10 +data/example/The complete poetical works and letters of John Keats, 1899.djvu279.txt georgiana▁augusta▁keats 4.0955944E+10 +data/example/Good news to Scotland (2).pdf2.txt master▁richard▁cameron 1.6211098E+11 +data/example/Good news to Scotland (1).pdf2.txt master▁richard▁cameron 1.6211098E+11 +data/example/St. Nicholas - Volume 41, Part 1.djvu59.txt thanksgiving 4.1471177E+11 +data/example/Elizabeth (Poe).txt elizabeth▁rebecca 1.6337993E+12 +data/example/The Old GuardVolume 1Issue 1Acrostic.txt george▁washington 3.5446523E+12 +data/example/The PearlVolume 18Acrostic.txt cunt▁is▁sweet▁when▁young▁and▁tender 3.6600743E+12 +data/example/The Confessions of William-Henry Ireland.txt warwick▁at▁dudley▁at▁southampton▁at▁rivers▁at▁shakspeare 7.6181055E+27 ``` ## How was AcrosticScout evaluated? diff --git a/acrostics.iml b/acrostics.iml index 1af4a9a..da0f2bd 100644 --- a/acrostics.iml +++ b/acrostics.iml @@ -10,6 +10,5 @@ - \ No newline at end of file diff --git a/data/evaluate_on_acrostics-identification-task-dataset.sh b/data/evaluate_on_acrostics-identification-task-dataset.sh index b735b70..ee985d5 100755 --- a/data/evaluate_on_acrostics-identification-task-dataset.sh +++ b/data/evaluate_on_acrostics-identification-task-dataset.sh @@ -4,10 +4,10 @@ cd "$parent_path" || exit cd ../ mkdir -p output -javac -encoding UTF-8 -cp src:lib/commons-cli-1.5.0.jar src/acrostics/*.java -java -cp src:lib/commons-cli-1.5.0.jar acrostics.Main -input data/acrostic-identification-task-dataset/en -language EN -mode LINE -charset utf-8 -outputSize 200000 --wikisource -workers 10 -models models/EN > output/en.tsv -java -cp src:lib/commons-cli-1.5.0.jar acrostics.Main -input data/acrostic-identification-task-dataset/ru -language RU -mode LINE -charset utf-8 -outputSize 200000 --wikisource -workers 10 -models models/RU > output/ru.tsv -java -cp src:lib/commons-cli-1.5.0.jar acrostics.Main -input data/acrostic-identification-task-dataset/fr -language FR -mode LINE -charset utf-8 -outputSize 200000 --wikisource -workers 10 -models models/FR > output/fr.tsv +javac -cp src -encoding UTF-8 src/acrostics/*.java +java -cp src acrostics.Main -input data/acrostic-identification-task-dataset/en -language EN -mode LINE -charset utf-8 -outputSize 200000 --wikisource -workers 10 -models models/EN > output/en.tsv +java -cp src acrostics.Main -input data/acrostic-identification-task-dataset/ru -language RU -mode LINE -charset utf-8 -outputSize 200000 --wikisource -workers 10 -models models/RU > output/ru.tsv +java -cp src acrostics.Main -input data/acrostic-identification-task-dataset/fr -language FR -mode LINE -charset utf-8 -outputSize 200000 --wikisource -workers 10 -models models/FR > output/fr.tsv cd data/acrostic-identification-task-dataset python3 scorer.py ../../RecallFigure.svg EN,labels/en.tsv,../../output/en.tsv,English RU,labels/ru.tsv,../../output/ru.tsv,Russian FR,labels/fr.tsv,../../output/fr.tsv,French # python3 scorer.py ../../EN_Figure.svg EN,labels/en.tsv,../../output/en72900.tsv,"72900 tokens LM" EN,labels/en.tsv,../../output/en24300.tsv,"24300 tokens LM" EN,labels/en.tsv,../../output/en8100.tsv,"8100 tokens LM" EN,labels/en.tsv,../../output/en2700.tsv,"2700 tokens LM" EN,labels/en.tsv,../../output/en900.tsv,"900 tokens LM" EN,labels/en.tsv,../../output/en300.tsv,"300 tokens LM" EN,labels/en.tsv,../../output/en100.tsv,"100 tokens LM" diff --git a/lib/commons-cli-1.5.0.jar b/lib/commons-cli-1.5.0.jar deleted file mode 100644 index e03645653bcd81b7ecdf1c98bf62d304e134fabe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58284 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 { + + @Option(names = {"-input", "--input"}, required = true, description = "File or directory with all texts of interest") + private String input; // list of all texts to be processed + public File[] texts; + + @Option(names = {"-outputSize", "--outputSize"}, description = "Max number of potential acrostics to print") + public int outputSize = OUTPUT_SIZE_DEFAULT; + + @Option(names = {"-models", "--models"}, description = "Prefix for a language model file.", hidden = true) + public String models; + + @Option(names = {"-maxLength", "--maxLength"}, description = "Maximum length of an acrostic (in characters). AcrosticScout will cluster longer acrostics together, so you probably don't want to modify this option.") + public int maxLength = MAX_LENGTH_DEFAULT; -public class CLO { // command line options + @Option(names = {"-workers", "--workers"}, description = "Number of threads to use") + public int workers = WORKERS_DEFAULT; - // Required Options: - public final File[] texts; // list of all texts to be processed + @Option(names = {"-mode", "--mode"}, description = "Look for acrostics formed by the first letter of each LINE or WORD") + public Mode mode = MODE_DEFAULT; - // Optional Options: - public final int outputSize; // max number of potential acrostics to print - public final String models; // Prefix for a language model file (either to read from or to save to) - public final int maxLength; // maximum length of an acrostic (in characters) - public final int workers; // number of threads to use - public final Mode mode; // use first letter of each line, word, or smth else - public final Charset charset; - public final Language language; // determines what preprocessing to do - public final boolean concise; // Report the lines that form the acrostic - public final boolean wikisource; // parse wikisource files into separate articles and report results accordingly + @Option(names = {"-charset", "--charset"}, description = "Name of the character encoding to use. Supports utf-8 and windows-1251") + public Charset charset = CHARSET_DEFAULT; + + @Option(names = {"-language", "--language"}, required = true, description = "Determines the language of the text: EN, LA, RU, FR") + public Language language; + + @Option(names = {"-concise", "--concise"}, description = "Report minimal information -- only the acrostic, the page it comes from, and the rank") + public boolean concise; + + @Option(names = {"-wikisource", "--wikisource"}, description = "Use if the input is a parsed WikiSource database, where there might be several texts per file.") + public boolean wikisource; - // Default Values: public static final int MAX_LENGTH_DEFAULT = 50; public static final int OUTPUT_SIZE_DEFAULT = 10000; public static final int WORKERS_DEFAULT = 1; public static final Mode MODE_DEFAULT = Mode.LINE; public static final Charset CHARSET_DEFAULT = StandardCharsets.UTF_8; - // Custom Constants: - // print that many tokens before and after each acrostic (not configurable) public static final int OUTPUT_MARGIN = 3; - CLO(String[] args) { - Options options = new Options(); - - Option index = new Option("input", "input", true, - "file or directory with all texts of interest"); - index.setRequired(true); - index.setType(String.class); - options.addOption(index); - - Option language = new Option("language", "language", true, - "Determines the text preprocessing steps:\n" + - "LA - latin alphabet + j=i and v=u \n" + - "EN - latin alphabet \n" + - "RU - russian alphabet - ьъ + ё=е."); - language.setRequired(true); - language.setType(String.class); - options.addOption(language); - - Option outputSize = new Option("outputSize", "outputSize", true, - "maximum number of potential acrostics to print." + - "Note that the actual number printed might be " + - "considerably lower if print is not set to ALL."); - outputSize.setOptionalArg(true); - outputSize.setType(Number.class); - options.addOption(outputSize); - - Option models = new Option("models", "models", true, - "prefix of the file from which to load/save to the models"); - models.setOptionalArg(true); - models.setType(String.class); - options.addOption(models); - - Option maxLength = new Option("maxLength", "maxLength", true, - "maximum length of an acrostic (in characters)"); - maxLength.setOptionalArg(true); - maxLength.setType(Number.class); - options.addOption(maxLength); - - Option workers = new Option("workers", "workers", true, - "number of threads to use"); - workers.setOptionalArg(true); - workers.setType(Number.class); - options.addOption(workers); - - Option mode = new Option("mode", "mode", true, - "Determines which letters to form a phrase from:\n" + - "LINE - first letter of each line, i.e. acrostic\n" + - "WORD - first letter of each word."); - mode.setOptionalArg(true); - mode.setType(String.class); - options.addOption(mode); - - Option charset = new Option("charset", "charset", true, - "Name of the character encoding to use.\n" + - "Supports utf-8 and windows-1251"); - charset.setOptionalArg(true); - charset.setType(String.class); - options.addOption(charset); - - Option wikisource = new Option("wikisource", "wikisource", false, - "Parse wikisource files into separate articles and report results accordingly"); - wikisource.setOptionalArg(true); - options.addOption(wikisource); - - Option concise = new Option("concise", "concise", false, - "Only report the acrostic, the file it comes from, and the rank, but omit all the extra information"); - concise.setOptionalArg(true); - options.addOption(concise); - - CommandLineParser parser = new DefaultParser(); - HelpFormatter formatter = new HelpFormatter(); - CommandLine cmd = null; - - try { - cmd = parser.parse(options, args); - } catch (ParseException e) { - System.err.println(e.getMessage()); - formatter.printHelp("utility-name", options); - System.exit(1); - } - - this.texts = listFiles(cmd.getOptionValue("input")); + @Override + public Integer call() { + this.texts = listFiles(input); if (this.texts == null) { - System.err.println("Could not find file or directory: " + cmd.getOptionValue("input")); - System.exit(1); + System.err.println("Could not find file or directory: " + input); + return 1; } else if (this.texts.length == 0) { - System.err.println("Directory is empty: " + cmd.getOptionValue("input")); - System.exit(1); + System.err.println("Directory is empty: " + input); + return 1; } - this.language = Language.get(cmd.getOptionValue("language")); - if (this.language == null) { - System.err.println("Language " + cmd.getOptionValue("language") + " is not supported. Please use one of EN, LA, FR, or RU"); - System.exit(1); + AcrosticCluster.concise = concise; + + if (models == null) { + models = Paths.get("models", language.label).toString(); } - this.outputSize = cmd.hasOption("outputSize") ? - Integer.parseInt(cmd.getOptionValue("outputSize")) : - OUTPUT_SIZE_DEFAULT; - this.maxLength = cmd.hasOption("maxLength") ? - Integer.parseInt(cmd.getOptionValue("maxLength")) : - MAX_LENGTH_DEFAULT; - this.workers = cmd.hasOption("workers") ? - Integer.parseInt(cmd.getOptionValue("workers")) : - WORKERS_DEFAULT; - this.mode = cmd.hasOption("mode") ? - Mode.get(cmd.getOptionValue("mode")) : - MODE_DEFAULT; - this.charset = cmd.hasOption("charset") ? - Charset.forName(cmd.getOptionValue("charset")) : - CHARSET_DEFAULT; - this.models = cmd.hasOption("models") ? - cmd.getOptionValue("models") : - Paths.get("models", this.language.label).toString(); - this.wikisource = cmd.hasOption(wikisource); - this.concise = cmd.hasOption(concise); - AcrosticCluster.concise = this.concise; + return 0; } private static File[] listFiles(String path) { diff --git a/src/acrostics/CommandLine.java b/src/acrostics/CommandLine.java new file mode 100644 index 0000000..6cd59c1 --- /dev/null +++ b/src/acrostics/CommandLine.java @@ -0,0 +1,19240 @@ +/* + Copyright 2017 Remko Popma + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +package acrostics; + +import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.*; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.NetworkInterface; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.text.BreakIterator; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import acrostics.CommandLine.Help.Ansi.IStyle; +import acrostics.CommandLine.Help.Ansi.Style; +import acrostics.CommandLine.Help.Ansi.Text; +import acrostics.CommandLine.Model.*; +import acrostics.CommandLine.ParseResult.GroupMatchContainer; + +import static java.util.Locale.ENGLISH; +import static acrostics.CommandLine.Help.Column.Overflow.SPAN; +import static acrostics.CommandLine.Help.Column.Overflow.TRUNCATE; +import static acrostics.CommandLine.Help.Column.Overflow.WRAP; + +/** + *

+ * CommandLine interpreter that uses reflection to initialize an annotated user object with values obtained from the + * command line arguments. + *

+ * The full user manual is hosted at https://acrostics.info. + *

Example

+ *

+ * An example that implements {@code Callable} and uses the {@link #execute(String...) CommandLine.execute} convenience API to run in a single line of code: + *

+ *
+ * @Command(name = "checksum", mixinStandardHelpOptions = true, version = "checksum 4.0",
+ *          description = "Prints the checksum (SHA-1 by default) of a file to STDOUT.")
+ * class CheckSum implements Callable<Integer> {
+ *
+ *     @Parameters(index = "0", description = "The file whose checksum to calculate.")
+ *     private File file;
+ *
+ *     @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")
+ *     private String algorithm = "SHA-1";
+ *
+ *     @Override
+ *     public Integer call() throws Exception { // your business logic goes here...
+ *         byte[] fileContents = Files.readAllBytes(file.toPath());
+ *         byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
+ *         System.out.printf("%0" + (digest.length*2) + "x%n", new BigInteger(1,digest));
+ *         return 0;
+ *     }
+ *
+ *     // CheckSum implements Callable, so parsing, error handling and handling user
+ *     // requests for usage help or version help can be done with one line of code.
+ *     public static void main(String[] args) {
+ *         int exitCode = new CommandLine(new CheckSum()).execute(args);
+ *         System.exit(exitCode);
+ *     }
+ * }
+ * 
+ *

Another example where the application calls {@code parseArgs} and takes responsibility + * for error handling and checking whether the user requested help:

+ *
import static acrostics.CommandLine.*;
+ *
+ * @Command(mixinStandardHelpOptions = true, version = "v3.0.0",
+ *         header = "Encrypt FILE(s), or standard input, to standard output or to the output file.")
+ * public class Encrypt {
+ *
+ *     @Parameters(description = "Any number of input files")
+ *     private List<File> files = new ArrayList<File>();
+ *
+ *     @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
+ *     private File outputFile;
+ *
+ *     @Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
+ *     private boolean[] verbose;
+ * }
+ * 
+ *

+ * Use {@code CommandLine} to initialize a user object as follows: + *

+ * public static void main(String... args) {
+ *     Encrypt encrypt = new Encrypt();
+ *     try {
+ *         ParseResult parseResult = new CommandLine(encrypt).parseArgs(args);
+ *         if (!CommandLine.printHelpIfRequested(parseResult)) {
+ *             runProgram(encrypt);
+ *         }
+ *     } catch (ParameterException ex) { // command line arguments could not be parsed
+ *         System.err.println(ex.getMessage());
+ *         ex.getCommandLine().usage(System.err);
+ *     }
+ * }
+ * 

+ * Invoke the above program with some command line arguments. The below are all equivalent: + *

+ *
+ * --verbose --out=outfile in1 in2
+ * --verbose --out outfile in1 in2
+ * -v --out=outfile in1 in2
+ * -v -o outfile in1 in2
+ * -v -o=outfile in1 in2
+ * -vo outfile in1 in2
+ * -vo=outfile in1 in2
+ * -v -ooutfile in1 in2
+ * -vooutfile in1 in2
+ * 
+ *

Classes and Interfaces for Defining a CommandSpec Model

+ *

+ * Classes and Interfaces for Defining a CommandSpec Model + *

+ *

Classes Related to Parsing Command Line Arguments

+ *

+ * Classes Related to Parsing Command Line Arguments + *

+ */ +public class CommandLine { + + /** This is acrostics version {@value}. */ + public static final String VERSION = "4.7.7-SNAPSHOT"; + private static final Tracer TRACER = new Tracer(); + + private CommandSpec commandSpec; + private final Interpreter interpreter; + private final IFactory factory; + + private Object executionResult; + private PrintWriter out; + private PrintWriter err; + private Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO); + private IExitCodeExceptionMapper exitCodeExceptionMapper; + private IExecutionStrategy executionStrategy = new RunLast(); + private IParameterExceptionHandler parameterExceptionHandler = new IParameterExceptionHandler() { + public int handleParseException(ParameterException ex, String[] args) { + CommandLine cmd = ex.getCommandLine(); + DefaultExceptionHandler.internalHandleParseException(ex, cmd.getErr(), cmd.getColorScheme()); + return mappedExitCode(ex, cmd.getExitCodeExceptionMapper(), cmd.getCommandSpec().exitCodeOnInvalidInput()); + } + }; + private IExecutionExceptionHandler executionExceptionHandler = new IExecutionExceptionHandler() { + public int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult parseResult) throws Exception { + throw ex; + } + }; + + /** + * Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and a default {@linkplain IFactory factory}. + *

The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated + * user object with {@code @Option} and {@code @Parameters}-annotated fields and methods, in which case acrostics automatically + * constructs a {@code CommandSpec} from this user object. + *

If the specified command object is an interface {@code Class} with {@code @Option} and {@code @Parameters}-annotated methods, + * acrostics creates a {@link java.lang.reflect.Proxy Proxy} whose methods return the matched command line values. + * If the specified command object is a concrete {@code Class}, acrostics delegates to the default factory to get an instance. + *

+ * If the specified object implements {@code Runnable} or {@code Callable}, or if it is a {@code Method} object, + * the command can be run as an application in a single line of code by using the + * {@link #execute(String...) execute} method to omit some boilerplate code for handling help requests and invalid input. + * See {@link #getCommandMethods(Class, String) getCommandMethods} for a convenient way to obtain a command {@code Method}. + *

+ * When the {@link #parseArgs(String...)} method is called, the {@link CommandSpec CommandSpec} object will be + * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this + * user object will be initialized based on the command line arguments. + *

+ * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + */ + public CommandLine(Object command) { + this(command, new DefaultFactory()); + } + /** + * Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and object factory. + *

The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated + * user object with {@code @Option} and {@code @Parameters}-annotated fields and methods, in which case acrostics automatically + * constructs a {@code CommandSpec} from this user object. + *

If the specified command object is an interface {@code Class} with {@code @Option} and {@code @Parameters}-annotated methods, + * acrostics creates a {@link java.lang.reflect.Proxy Proxy} whose methods return the matched command line values. + * If the specified command object is a concrete {@code Class}, acrostics delegates to the {@linkplain IFactory factory} to get an instance. + *

+ * If the specified object implements {@code Runnable} or {@code Callable}, or if it is a {@code Method} object, + * the command can be run as an application in a single line of code by using the + * {@link #execute(String...) execute} method to omit some boilerplate code for handling help requests and invalid input. + * See {@link #getCommandMethods(Class, String) getCommandMethods} for a convenient way to obtain a command {@code Method}. + *

+ * When the {@link #parseArgs(String...)} method is called, the {@link CommandSpec CommandSpec} object will be + * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this + * user object will be initialized based on the command line arguments. + *

+ * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments + * @param factory the factory used to create instances of {@linkplain Command#subcommands() subcommands}, {@linkplain Option#converter() converters}, etc., that are registered declaratively with annotation attributes + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @since 2.2 */ + public CommandLine(Object command, IFactory factory) { + this(command, factory, true); + } + + private CommandLine(Object command, IFactory factory, boolean userCalled) { + this.factory = Assert.notNull(factory, "factory"); + interpreter = new Interpreter(); + commandSpec = CommandSpec.forAnnotatedObject(command, factory); + commandSpec.commandLine(this); + if (userCalled) { this.applyModelTransformations(); } + commandSpec.validate(); + if (commandSpec.unmatchedArgsBindings().size() > 0) { setUnmatchedArgumentsAllowed(true); } + } + + /** Apply transformers to command spec recursively. */ + private void applyModelTransformations() { + if (commandSpec.modelTransformer != null) { + commandSpec = commandSpec.modelTransformer.transform(commandSpec); + } + for (CommandLine cmd : getSubcommands().values()) { + cmd.applyModelTransformations(); + } + } + + private CommandLine copy() { + CommandLine result = new CommandLine(commandSpec.copy(), factory); // create a new sub-hierarchy + result.err = err; + result.out = out; + result.colorScheme = colorScheme; + result.executionStrategy = executionStrategy; + result.exitCodeExceptionMapper = exitCodeExceptionMapper; + result.executionExceptionHandler = executionExceptionHandler; + result.parameterExceptionHandler = parameterExceptionHandler; + + result.interpreter.converterRegistry.clear(); + result.interpreter.converterRegistry.putAll(interpreter.converterRegistry); + return result; + } + + /** + * Returns the {@code CommandSpec} model that this {@code CommandLine} was constructed with. + * @return the {@code CommandSpec} model + * @since 3.0 */ + public CommandSpec getCommandSpec() { return commandSpec; } + + /** + * Adds the options and positional parameters in the specified mixin to this command. + *

The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a user object with + * {@code @Option} and {@code @Parameters}-annotated fields, in which case acrostics automatically + * constructs a {@code CommandSpec} from this user object. + *

+ * @param name the name by which the mixin object may later be retrieved + * @param mixin an annotated user object or a {@link CommandSpec CommandSpec} object whose options and positional parameters to add to this command + * @return this CommandLine object, to allow method chaining + * @since 3.0 */ + public CommandLine addMixin(String name, Object mixin) { + getCommandSpec().addMixin(name, CommandSpec.forAnnotatedObject(mixin, factory)); + return this; + } + + /** + * Returns a map of user objects whose options and positional parameters were added to ("mixed in" with) this command. + * @return a new Map containing the user objects mixed in with this command. If {@code CommandSpec} objects without + * user objects were programmatically added, use the {@link CommandSpec#mixins() underlying model} directly. + * @since 3.0 */ + public Map getMixins() { + Map mixins = getCommandSpec().mixins(); + Map result = new LinkedHashMap(); + for (String name : mixins.keySet()) { result.put(name, mixins.get(name).userObject.getInstance()); } + return result; + } + + /** Registers a subcommand with the name obtained from the {@code @Command(name = "...")} {@linkplain Command#name() annotation attribute} of the specified command. + * @param command the object to initialize with command line arguments following the subcommand name. + * This may be a {@code Class} that has a {@code @Command} annotation, or an instance of such a + * class, or a {@code CommandSpec} or {@code CommandLine} instance with its own (nested) subcommands. + * @return this CommandLine object, to allow method chaining + * @since 4.0 + * @throws InitializationException if no name could be found for the specified subcommand, + * or if another subcommand was already registered under the same name, or if one of the aliases + * of the specified subcommand was already used by another subcommand. + * @see #addSubcommand(String, Object) */ + public CommandLine addSubcommand(Object command) { + return addSubcommand(null, command, new String[0]); + } + + /** Registers a subcommand with the specified name. For example: + *
+     * CommandLine commandLine = new CommandLine(new Git())
+     *         .addSubcommand("status",   new GitStatus())
+     *         .addSubcommand("commit",   new GitCommit();
+     *         .addSubcommand("add",      new GitAdd())
+     *         .addSubcommand("branch",   new GitBranch())
+     *         .addSubcommand("checkout", new GitCheckout())
+     *         //...
+     *         ;
+     * 
+ * + *

The specified object can be an annotated object or a + * {@code CommandLine} instance with its own nested subcommands. For example:

+ *
+     * CommandLine commandLine = new CommandLine(new MainCommand())
+     *         .addSubcommand("cmd1",                 new ChildCommand1()) // subcommand
+     *         .addSubcommand("cmd2",                 new ChildCommand2())
+     *         .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // subcommand with nested sub-subcommands
+     *                 .addSubcommand("cmd3sub1",                 new GrandChild3Command1())
+     *                 .addSubcommand("cmd3sub2",                 new GrandChild3Command2())
+     *                 .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // deeper nesting
+     *                         .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
+     *                         .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
+     *                 )
+     *         );
+     * 
+ *

The default type converters are available on all subcommands and nested sub-subcommands, but custom type + * converters are registered only with the subcommand hierarchy as it existed when the custom type was registered. + * To ensure a custom type converter is available to all subcommands, register the type converter last, after + * adding subcommands.

+ *

See also the {@link Command#subcommands()} annotation to register subcommands declaratively.

+ * + * @param name the string to recognize on the command line as a subcommand. + * If {@code null}, the {@linkplain CommandSpec#name() name} of the specified subcommand is used; + * if this is also {@code null}, the first {@linkplain CommandSpec#aliases() alias} is used. + * @param command the object to initialize with command line arguments following the subcommand name. + * This may be a {@code Class} that has a {@code @Command} annotation, or an instance of such a + * class, or a {@code CommandSpec} or {@code CommandLine} instance with its own (nested) subcommands. + * @return this CommandLine object, to allow method chaining + * @see #registerConverter(Class, ITypeConverter) + * @since 0.9.7 + * @see Command#subcommands() + * @throws InitializationException if the specified name is {@code null}, and no alternative name could be found, + * or if another subcommand was already registered under the same name, or if one of the aliases + * of the specified subcommand was already used by another subcommand. + */ + public CommandLine addSubcommand(String name, Object command) { + return addSubcommand(name, command, new String[0]); + } + + /** Registers a subcommand with the specified name and all specified aliases. See also {@link #addSubcommand(String, Object)}. + * @param name the string to recognize on the command line as a subcommand. + * If {@code null}, the {@linkplain CommandSpec#name() name} of the specified subcommand is used; + * if this is also {@code null}, the first {@linkplain CommandSpec#aliases() alias} is used. + * @param command the object to initialize with command line arguments following the subcommand name. + * This may be a {@code Class} that has a {@code @Command} annotation, or an instance of such a + * class, or a {@code CommandSpec} or {@code CommandLine} instance with its own (nested) subcommands. + * @param aliases zero or more alias names that are also recognized on the command line as this subcommand + * @return this CommandLine object, to allow method chaining + * @since 3.1 + * @see #addSubcommand(String, Object) + * @throws InitializationException if the specified name is {@code null}, and no alternative name could be found, + * or if another subcommand was already registered under the same name, or if one of the aliases + * of the specified subcommand was already used by another subcommand. + */ + public CommandLine addSubcommand(String name, Object command, String... aliases) { + CommandLine subcommandLine = toCommandLine(command, factory); + subcommandLine.getCommandSpec().aliases.addAll(Arrays.asList(aliases)); + getCommandSpec().addSubcommand(name, subcommandLine); + return this; + } + /** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance. + * @return a map with the registered subcommands + * @since 0.9.7 + */ + public Map getSubcommands() { + return new CaseAwareLinkedMap(getCommandSpec().commands); + } + /** + * Returns the command that this is a subcommand of, or {@code null} if this is a top-level command. + * @return the command that this is a subcommand of, or {@code null} if this is a top-level command + * @see #addSubcommand(String, Object) + * @see Command#subcommands() + * @since 0.9.8 + */ + public CommandLine getParent() { + CommandSpec parent = getCommandSpec().parent(); + return parent == null ? null : parent.commandLine(); + } + + /** Returns the annotated user object that this {@code CommandLine} instance was constructed with. + * @param the type of the variable that the return value is being assigned to + * @return the annotated object that this {@code CommandLine} instance was constructed with + * @since 0.9.7 + */ + @SuppressWarnings("unchecked") + public T getCommand() { + return (T) getCommandSpec().userObject(); + } + + /** Returns the factory that this {@code CommandLine} was constructed with. + * @return the factory that this {@code CommandLine} was constructed with, never {@code null} + * @since 4.6 */ + public IFactory getFactory() { return factory; } + + /** Returns {@code true} if an option annotated with {@link Option#usageHelp()} was specified on the command line. + * @return whether the parser encountered an option annotated with {@link Option#usageHelp()}. + * @since 0.9.8 */ + public boolean isUsageHelpRequested() { return interpreter.parseResultBuilder != null && interpreter.parseResultBuilder.usageHelpRequested; } + + /** Returns {@code true} if an option annotated with {@link Option#versionHelp()} was specified on the command line. + * @return whether the parser encountered an option annotated with {@link Option#versionHelp()}. + * @since 0.9.8 */ + public boolean isVersionHelpRequested() { return interpreter.parseResultBuilder != null && interpreter.parseResultBuilder.versionHelpRequested; } + /** Returns a new {@code Help} object created by the {@code IHelpFactory} with the {@code CommandSpec} and {@code ColorScheme} of this command. + * @see Help#Help(CommandSpec, Help.ColorScheme) + * @see #getHelpFactory() + * @see #getCommandSpec() + * @see #getColorScheme() + * @since 4.1 + */ + public Help getHelp() { + return getHelpFactory().create(getCommandSpec(), getColorScheme()); + } + /** Returns the {@code IHelpFactory} that is used to construct the usage help message. + * @see #setHelpFactory(IHelpFactory) + * @since 3.9 + */ + public IHelpFactory getHelpFactory() { + return getCommandSpec().usageMessage().helpFactory(); + } + + /** Sets a new {@code IHelpFactory} to customize the usage help message. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param helpFactory the new help factory. Must be non-{@code null}. + * @return this {@code CommandLine} object, to allow method chaining + * @since 3.9 + */ + public CommandLine setHelpFactory(IHelpFactory helpFactory) { + getCommandSpec().usageMessage().helpFactory(helpFactory); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setHelpFactory(helpFactory); + } + return this; + } + + /** + * Returns the section keys in the order that the usage help message should render the sections. + * This ordering may be modified with {@link #setHelpSectionKeys(List) setSectionKeys}. The default keys are (in order): + *
    + *
  1. {@link UsageMessageSpec#SECTION_KEY_HEADER_HEADING SECTION_KEY_HEADER_HEADING}
  2. + *
  3. {@link UsageMessageSpec#SECTION_KEY_HEADER SECTION_KEY_HEADER}
  4. + *
  5. {@link UsageMessageSpec#SECTION_KEY_SYNOPSIS_HEADING SECTION_KEY_SYNOPSIS_HEADING}
  6. + *
  7. {@link UsageMessageSpec#SECTION_KEY_SYNOPSIS SECTION_KEY_SYNOPSIS}
  8. + *
  9. {@link UsageMessageSpec#SECTION_KEY_DESCRIPTION_HEADING SECTION_KEY_DESCRIPTION_HEADING}
  10. + *
  11. {@link UsageMessageSpec#SECTION_KEY_DESCRIPTION SECTION_KEY_DESCRIPTION}
  12. + *
  13. {@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST_HEADING SECTION_KEY_PARAMETER_LIST_HEADING}
  14. + *
  15. {@link UsageMessageSpec#SECTION_KEY_AT_FILE_PARAMETER SECTION_KEY_AT_FILE_PARAMETER}
  16. + *
  17. {@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST SECTION_KEY_PARAMETER_LIST}
  18. + *
  19. {@link UsageMessageSpec#SECTION_KEY_OPTION_LIST_HEADING SECTION_KEY_OPTION_LIST_HEADING}
  20. + *
  21. {@link UsageMessageSpec#SECTION_KEY_OPTION_LIST SECTION_KEY_OPTION_LIST}
  22. + *
  23. {@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST_HEADING SECTION_KEY_COMMAND_LIST_HEADING}
  24. + *
  25. {@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST SECTION_KEY_COMMAND_LIST}
  26. + *
  27. {@link UsageMessageSpec#SECTION_KEY_EXIT_CODE_LIST_HEADING SECTION_KEY_EXIT_CODE_LIST_HEADING}
  28. + *
  29. {@link UsageMessageSpec#SECTION_KEY_EXIT_CODE_LIST SECTION_KEY_EXIT_CODE_LIST}
  30. + *
  31. {@link UsageMessageSpec#SECTION_KEY_FOOTER_HEADING SECTION_KEY_FOOTER_HEADING}
  32. + *
  33. {@link UsageMessageSpec#SECTION_KEY_FOOTER SECTION_KEY_FOOTER}
  34. + *
+ * @since 3.9 + */ + public List getHelpSectionKeys() { return getCommandSpec().usageMessage().sectionKeys(); } + + /** + * Sets the section keys in the order that the usage help message should render the sections. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ *

Use {@link UsageMessageSpec#sectionKeys(List)} to customize a command without affecting its subcommands.

+ * @see #getHelpSectionKeys + * @since 3.9 + */ + public CommandLine setHelpSectionKeys(List keys) { + getCommandSpec().usageMessage().sectionKeys(keys); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setHelpSectionKeys(keys); + } + return this; + } + + /** + * Returns the map of section keys and renderers used to construct the usage help message. + * The usage help message can be customized by adding, replacing and removing section renderers from this map. + * Sections can be reordered with {@link #setHelpSectionKeys(List) setSectionKeys}. + * Sections that are either not in this map or not in the list returned by {@link #getHelpSectionKeys() getSectionKeys} are omitted. + *

+ * NOTE: By modifying the returned {@code Map}, only the usage help message of this command is affected. + * Use {@link #setHelpSectionMap(Map)} to customize the usage help message for this command and all subcommands. + *

+ * @since 3.9 + */ + public Map getHelpSectionMap() { return getCommandSpec().usageMessage().sectionMap(); } + + /** + * Sets the map of section keys and renderers used to construct the usage help message. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ *

Use {@link UsageMessageSpec#sectionMap(Map)} to customize a command without affecting its subcommands.

+ * @see #getHelpSectionMap + * @since 3.9 + */ + public CommandLine setHelpSectionMap(Map map) { + getCommandSpec().usageMessage().sectionMap(map); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setHelpSectionMap(map); + } + return this; + } + /** + * Returns whether line breaks should take wide Chinese, Japanese and Korean characters into account for line-breaking purposes. The default is {@code true}. + * @return true if wide Chinese, Japanese and Korean characters are counted as double the size of other characters for line-breaking purposes + * @since 4.0 */ + public boolean isAdjustLineBreaksForWideCJKCharacters() { return getCommandSpec().usageMessage().adjustLineBreaksForWideCJKCharacters(); } + /** Sets whether line breaks should take wide Chinese, Japanese and Korean characters into account, and returns this UsageMessageSpec. The default is {@code true}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param adjustForWideChars if true, wide Chinese, Japanese and Korean characters are counted as double the size of other characters for line-breaking purposes + * @since 4.0 */ + public CommandLine setAdjustLineBreaksForWideCJKCharacters(boolean adjustForWideChars) { + getCommandSpec().usageMessage().adjustLineBreaksForWideCJKCharacters(adjustForWideChars); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setAdjustLineBreaksForWideCJKCharacters(adjustForWideChars); + } + return this; + } + + /** Returns whether the value of boolean flag options should be "toggled" when the option is matched. + * From 4.0, this is {@code false} by default, and when a flag option is specified on the command line acrostics + * will set its value to the opposite of its default value. + * If this method returns {@code true}, flags are toggled, so if the value is {@code true} it is + * set to {@code false}, and when the value is {@code false} it is set to {@code true}. + * When toggling is enabled, specifying a flag option twice on the command line will have no effect because they cancel each other out. + * @return {@code true} the value of boolean flag options should be "toggled" when the option is matched, {@code false} otherwise + * @since 3.0 + */ + public boolean isToggleBooleanFlags() { + return getCommandSpec().parser().toggleBooleanFlags(); + } + + /** Sets whether the value of boolean flag options should be "toggled" when the option is matched. The default is {@code false}, + * and when a flag option is specified on the command line acrostics will set its value to the opposite of its default value. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 3.0 + */ + public CommandLine setToggleBooleanFlags(boolean newValue) { + getCommandSpec().parser().toggleBooleanFlags(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setToggleBooleanFlags(newValue); + } + return this; + } + + /** Returns whether variables should be interpolated in String values. The default is {@code true}. + * @since 4.0 */ + public boolean isInterpolateVariables() { return getCommandSpec().interpolateVariables(); } + /** Sets whether variables should be interpolated in String values. The default is {@code true}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @since 4.0 */ + public CommandLine setInterpolateVariables(boolean interpolate) { + getCommandSpec().interpolateVariables(interpolate); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setInterpolateVariables(interpolate); + } + return this; + } + + /** Returns whether options for single-value fields can be specified multiple times on the command line. + * The default is {@code false} and a {@link OverwrittenOptionException} is thrown if this happens. + * When {@code true}, the last specified value is retained. + * @return {@code true} if options for single-value fields can be specified multiple times on the command line, {@code false} otherwise + * @since 0.9.7 + */ + public boolean isOverwrittenOptionsAllowed() { + return getCommandSpec().parser().overwrittenOptionsAllowed(); + } + + /** Sets whether options for single-value fields can be specified multiple times on the command line without a {@link OverwrittenOptionException} being thrown. + * The default is {@code false}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 0.9.7 + */ + public CommandLine setOverwrittenOptionsAllowed(boolean newValue) { + getCommandSpec().parser().overwrittenOptionsAllowed(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setOverwrittenOptionsAllowed(newValue); + } + return this; + } + + /** Returns whether the parser accepts clustered short options. The default is {@code true}. + * @return {@code true} if short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}, {@code false} otherwise + * @since 3.0 */ + public boolean isPosixClusteredShortOptionsAllowed() { return getCommandSpec().parser().posixClusteredShortOptionsAllowed(); } + + /** Sets whether short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}. The default is {@code true}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 3.0 + */ + public CommandLine setPosixClusteredShortOptionsAllowed(boolean newValue) { + getCommandSpec().parser().posixClusteredShortOptionsAllowed(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setPosixClusteredShortOptionsAllowed(newValue); + } + return this; + } + + /** Returns whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}. + * @return {@code true} if enum values can be specified that don't match the {@code toString()} value of the enum constant, {@code false} otherwise; + * e.g., for an option of type java.time.DayOfWeek, + * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}. + * @since 3.4 */ + public boolean isCaseInsensitiveEnumValuesAllowed() { return getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(); } + + /** Sets whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}. + * When set to true, for example, for an option of type java.time.DayOfWeek, + * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 3.4 + */ + public CommandLine setCaseInsensitiveEnumValuesAllowed(boolean newValue) { + getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setCaseInsensitiveEnumValuesAllowed(newValue); + } + return this; + } + + /** Returns whether the parser should trim quotes from command line arguments. The default is + * read from the system property "acrostics.trimQuotes" and will be {@code true} if the property is present and empty, + * or if its value is "true". + *

If this property is set to {@code true}, the parser will remove quotes from the command line arguments, as follows:

+ *
    + *
  • if the command line argument contains just the leading and trailing quote, these quotes are removed
  • + *
  • if the command line argument contains more quotes than just the leading and trailing quote, the parser first + * tries to process the parameter with the quotes intact. For example, the {@code split} regular expression inside + * a quoted region should be ignored, so arguments like {@code "a,b","x,y"} are handled correctly. + * For arguments with nested quotes, quotes are removed later in the processing pipeline, after {@code split} operations are applied.
  • + *
+ * @return {@code true} if the parser should trim quotes from command line arguments before processing them, {@code false} otherwise; + * @see ParserSpec#trimQuotes() + * @since 3.7 */ + public boolean isTrimQuotes() { return getCommandSpec().parser().trimQuotes(); } + + /** Sets whether the parser should trim quotes from command line arguments before processing them. The default is + * read from the system property "acrostics.trimQuotes" and will be {@code true} if the property is set and empty, or + * if its value is "true". + *

If this property is set to {@code true}, the parser will remove quotes from the command line arguments, as follows:

+ *
    + *
  • if the command line argument contains just the leading and trailing quote, these quotes are removed
  • + *
  • if the command line argument contains more quotes than just the leading and trailing quote, the parser first + * tries to process the parameter with the quotes intact. For example, the {@code split} regular expression inside + * a quoted region should be ignored, so arguments like {@code "a,b","x,y"} are handled correctly. + * For arguments with nested quotes, quotes are removed later in the processing pipeline, after {@code split} operations are applied.
  • + *
+ *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ *

Calling this method will cause the "acrostics.trimQuotes" property to have no effect.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @see ParserSpec#trimQuotes(boolean) + * @since 3.7 + */ + public CommandLine setTrimQuotes(boolean newValue) { + getCommandSpec().parser().trimQuotes(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setTrimQuotes(newValue); + } + return this; + } + + /** Returns whether the parser is allowed to split quoted Strings or not. The default is {@code false}, + * so quotes are respected: quoted strings are treated as a single value that should not be broken up. + *

+ * For example, take a single command line parameter {@code "a,b","x,y"}. With a comma split regex, the default of {@code splitQuotedStrings = false} + * means that this value will be split into two strings: {@code "a,b"} and {@code "x,y"}. This is usually what you want. + *

+ * If {@code splitQuotedStrings} is set to {@code true}, quotes are not respected, and the value is split up into four parts: + * the first is {@code "a}, the second is {@code b"}, the third is {@code "x}, and the last part is {@code y"}. This is generally not what you want. + *

+ * @deprecated Most applications should not change the default. The rare application that does need to split parameter values + * without respecting quotes should use {@link ParserSpec#splitQuotedStrings(boolean)}. + * @return {@code true} if the parser is allowed to split quoted Strings, {@code false} otherwise; + * @see ArgSpec#splitRegex() + * @see ParserSpec#splitQuotedStrings() + * @since 3.7 */ + @Deprecated public boolean isSplitQuotedStrings() { return getCommandSpec().parser().splitQuotedStrings(); } + + /** Sets whether the parser is allowed to split quoted Strings. The default is {@code false}, + * so quotes are respected: quoted strings are treated as a single value that should not be broken up. + *

+ * For example, take a single command line parameter {@code "a,b","x,y"}. With a comma split regex, the default of {@code splitQuotedStrings = false} + * means that this value will be split into two strings: {@code "a,b"} and {@code "x,y"}. This is usually what you want. + *

+ * However, if {@code splitQuotedStrings} is set to {@code true}, quotes are not respected, and the value is split up into four parts: + * the first is {@code "a}, the second is {@code b"}, the third is {@code "x}, and the last part is {@code y"}. This is generally not what you want. + *

+ *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @deprecated Most applications should not change the default. The rare application that does need to split parameter values + * without respecting quotes should use {@link ParserSpec#splitQuotedStrings(boolean)}. + * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @see ArgSpec#splitRegex() + * @see ParserSpec#splitQuotedStrings(boolean) + * @since 3.7 + */ + @Deprecated public CommandLine setSplitQuotedStrings(boolean newValue) { + getCommandSpec().parser().splitQuotedStrings(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setSplitQuotedStrings(newValue); + } + return this; + } + + /** Returns the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters. + * @return the end-of-options delimiter. The default is {@code "--"}. + * @since 3.5 */ + public String getEndOfOptionsDelimiter() { return getCommandSpec().parser().endOfOptionsDelimiter(); } + + /** Sets the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters. + * @param delimiter the end-of-options delimiter; must not be {@code null}. The default is {@code "--"}. + * @return this {@code CommandLine} object, to allow method chaining + * @since 3.5 */ + public CommandLine setEndOfOptionsDelimiter(String delimiter) { + getCommandSpec().parser().endOfOptionsDelimiter(delimiter); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setEndOfOptionsDelimiter(delimiter); + } + return this; + } + + /** Returns whether upper case and lower case should be ignored when matching subcommands. The default is {@code false}. + * @return {@code true} if subcommands can be matched when they differ only in case from the {@code getCommandName()} value of a registered one, {@code false} otherwise. + * For example, if true, for a subcommand with name {@code help}, inputs like {@code help}, {@code HeLp} and {@code HELP} are all recognized. + * @since 4.3 */ + public boolean isSubcommandsCaseInsensitive() { return getCommandSpec().subcommandsCaseInsensitive(); } + + /** Sets whether upper case and lower case should be ignored when matching subcommands. The default is {@code false}. + * For example, when set to {@code true}, for a subcommand with name {@code help}, inputs like {@code help}, {@code HeLp} and {@code HELP} are all recognized. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.3 + */ + public CommandLine setSubcommandsCaseInsensitive(boolean newValue) { + getCommandSpec().subcommandsCaseInsensitive(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setSubcommandsCaseInsensitive(newValue); + } + return this; + } + + /** Returns whether upper case and lower case should be ignored when matching option names. The default is {@code false}. + * @return {@code true} if options can be matched when they differ only in case from the {@code names()} value of a registered one, {@code false} otherwise; + * For example, if true, for an option with name {@code -h}, inputs like {@code -h}, {@code -H} are both recognized. + * @since 4.3 */ + public boolean isOptionsCaseInsensitive() { return getCommandSpec().optionsCaseInsensitive(); } + + /** Sets whether upper case and lower case should be ignored when matching option names. The default is {@code false}. + * For example, when set to {@code true}, for an option with name {@code -h}, inputs like {@code -h}, {@code -H} are both recognized. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * Note that changing case sensitivity will also change the case sensitivity of {@linkplain Option#negatable() negatable} options: + * any custom {@link INegatableOptionTransformer} that was previously installed will be replaced by the case-insensitive + * version of the default transformer. To ensure your custom transformer is used, install it last, after changing case sensitivity. + * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.3 + */ + public CommandLine setOptionsCaseInsensitive(boolean newValue) { + getCommandSpec().optionsCaseInsensitive(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setOptionsCaseInsensitive(newValue); + } + return this; + } + + /** Returns whether abbreviation of subcommands should be allowed when matching subcommands. The default is {@code false}. + * @return {@code true} if subcommands can be matched when they are abbreviations of the {@code getCommandName()} value of a registered one, {@code false} otherwise. + * For example, if true, for a subcommand with name {@code helpCommand}, inputs like {@code h}, {@code h-c} and {@code hC} are all recognized. + * @since 4.4 */ + public boolean isAbbreviatedSubcommandsAllowed() { + return getCommandSpec().parser().abbreviatedSubcommandsAllowed(); + } + + /** Sets whether abbreviated subcommands should be matched. The default is {@code false}. + * For example, when set to {@code true}, for a subcommand {@code helpCommand}, inputs like {@code h}, {@code h-c} and {@code hC} are all recognized. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.4 + */ + public CommandLine setAbbreviatedSubcommandsAllowed(boolean newValue) { + getCommandSpec().parser().abbreviatedSubcommandsAllowed(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setAbbreviatedSubcommandsAllowed(newValue); + } + return this; + } + + /** Returns whether abbreviation of option names should be allowed when matching options. The default is {@code false}. + * @return {@code true} if options can be matched when they are abbreviations of the {@code names()} value of a registered one, {@code false} otherwise. + * For example, if true, for a subcommand with name {@code --helpMe}, inputs like {@code --h}, {@code --h-m} and {@code --hM} are all recognized. + * @since 4.4 */ + public boolean isAbbreviatedOptionsAllowed() { + return getCommandSpec().parser().abbreviatedOptionsAllowed(); + } + + /** Sets whether abbreviated option names should be matched. The default is {@code false}. + * For example, when set to {@code true}, for an option with name {@code --helpMe}, inputs like {@code --h}, {@code --h-m} and {@code --hM} are all recognized. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.4 + */ + public CommandLine setAbbreviatedOptionsAllowed(boolean newValue) { + getCommandSpec().parser().abbreviatedOptionsAllowed(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setAbbreviatedOptionsAllowed(newValue); + } + return this; + } + + /** Returns the default value provider for the command, or {@code null} if none has been set. + * @return the default value provider for this command, or {@code null} + * @since 3.6 + * @see Command#defaultValueProvider() + * @see CommandSpec#defaultValueProvider() + * @see ArgSpec#defaultValueString() + */ + public IDefaultValueProvider getDefaultValueProvider() { + return getCommandSpec().defaultValueProvider(); + } + + /** Sets a default value provider for the command and sub-commands + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * sub-commands and nested sub-subcommands at the moment this method is called. Sub-commands added + * later will have the default setting. To ensure a setting is applied to all + * sub-commands, call the setter last, after adding sub-commands.

+ * @param newValue the default value provider to use + * @return this {@code CommandLine} object, to allow method chaining + * @since 3.6 + */ + public CommandLine setDefaultValueProvider(IDefaultValueProvider newValue) { + getCommandSpec().defaultValueProvider(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setDefaultValueProvider(newValue); + } + return this; + } + + /** Returns whether the parser interprets the first positional parameter as "end of options" so the remaining + * arguments are all treated as positional parameters. The default is {@code false}. + * @return {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise + * @since 2.3 + */ + public boolean isStopAtPositional() { + return getCommandSpec().parser().stopAtPositional(); + } + + /** Sets whether the parser interprets the first positional parameter as "end of options" so the remaining + * arguments are all treated as positional parameters. The default is {@code false}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise + * @return this {@code CommandLine} object, to allow method chaining + * @since 2.3 + */ + public CommandLine setStopAtPositional(boolean newValue) { + getCommandSpec().parser().stopAtPositional(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setStopAtPositional(newValue); + } + return this; + } + + /** Returns whether the parser should stop interpreting options and positional parameters as soon as it encounters an + * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or + * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited). + * The default is {@code false}. + *

Setting this flag to {@code true} automatically sets the {@linkplain #isUnmatchedArgumentsAllowed() unmatchedArgumentsAllowed} flag to {@code true} also.

+ * @return {@code true} when an unmatched option should result in the remaining command line arguments to be added to the + * {@linkplain #getUnmatchedArguments() unmatchedArguments list} + * @since 2.3 + */ + public boolean isStopAtUnmatched() { + return getCommandSpec().parser().stopAtUnmatched(); + } + + /** Sets whether the parser should stop interpreting options and positional parameters as soon as it encounters an + * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or + * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited). + * The default is {@code false}. + *

Setting this flag to {@code true} automatically sets the {@linkplain #setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} flag to {@code true} also.

+ *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue {@code true} when an unmatched option should result in the remaining command line arguments to be added to the + * {@linkplain #getUnmatchedArguments() unmatchedArguments list} + * @return this {@code CommandLine} object, to allow method chaining + * @since 2.3 + */ + public CommandLine setStopAtUnmatched(boolean newValue) { + getCommandSpec().parser().stopAtUnmatched(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setStopAtUnmatched(newValue); + } + if (newValue) { setUnmatchedArgumentsAllowed(true); } + return this; + } + /** Returns whether options can have parameter values that match subcommand names or aliases, + * or whether such values should be rejected with a missing parameter exception. + * The default is {@code false}, so by default input like {@code -x=subcommand} is rejected if {@code -x} is an option that takes a String parameter, and {@code subcommand} is a subcommand of this command. + * @return {@code true} when options can have parameter values that match subcommand names or aliases, {@code false} when such values should be rejected with a missing parameter exception + * @since 4.7.7-SNAPSHOT + * @see ParserSpec#allowSubcommandsAsOptionParameters() + */ + public boolean isAllowSubcommandsAsOptionParameters() { + return getCommandSpec().parser().allowSubcommandsAsOptionParameters(); + } + /** Sets whether options can have parameter values that match subcommand names or aliases, or whether such values should be rejected with a missing parameter exception. + * The default is {@code false}, so by default + * input like {@code -x=subcommand} is rejected if {@code -x} is an option that takes a String parameter, and {@code subcommand} is a subcommand of this command. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting. When {@code true}, options can have parameter values that match subcommand names or aliases, when {@code false}, such values are rejected with a missing parameter exception + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.7.7-SNAPSHOT + * @see ParserSpec#allowSubcommandsAsOptionParameters(boolean) + */ + public CommandLine setAllowSubcommandsAsOptionParameters(boolean newValue) { + getCommandSpec().parser().allowSubcommandsAsOptionParameters(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setAllowSubcommandsAsOptionParameters(newValue); + } + return this; + } + /** Returns whether options can have parameter values that match the name of an option in this command, + * or whether such values should be rejected with a missing parameter exception. + * The default is {@code false}, so by default input like {@code -x=--some-option} is rejected if {@code -x} is an option that takes a String parameter, and {@code --some-option} is an option of this command. + *

This method only considers actual options of this command, as opposed to {@link #isUnmatchedOptionsAllowedAsOptionParameters()}, which considers values that resemble options.

+ * @return {@code true} when options can have parameter values that match the name of an option in this command, {@code false} when such values should be rejected with a missing parameter exception + * @since 4.7.7-SNAPSHOT + * @see #isUnmatchedOptionsAllowedAsOptionParameters() + * @see ParserSpec#allowOptionsAsOptionParameters() + */ + public boolean isAllowOptionsAsOptionParameters() { + return getCommandSpec().parser().allowOptionsAsOptionParameters(); + } + /** Sets whether options can have parameter values that match the name of an option in this command, or whether such values should be rejected with a missing parameter exception. + * The default is {@code false}, so by default + * input like {@code -x=--some-option} is rejected if {@code -x} is an option that takes a String parameter, and {@code --some-option} is an option of this command. + *

This method only considers actual options of this command, as opposed to {@link #setUnmatchedOptionsAllowedAsOptionParameters(boolean)}, which considers values that resemble options.

+ *

Use with caution! When set to {@code true}, any option in the command will consume the maximum number of arguments possible for its arity. + * This means that an option with {@code arity = "*"} will consume all command line arguments following that option. + * If this is not what you want, consider custom parameter processing.

+ *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting. When {@code true}, options can have parameter values that match the name of an option in this command, when {@code false}, such values are rejected with a missing parameter exception + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.7.7-SNAPSHOT + * @see #setUnmatchedOptionsAllowedAsOptionParameters(boolean) + * @see ParserSpec#allowOptionsAsOptionParameters(boolean) + */ + public CommandLine setAllowOptionsAsOptionParameters(boolean newValue) { + getCommandSpec().parser().allowOptionsAsOptionParameters(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setAllowOptionsAsOptionParameters(newValue); + } + return this; + } + + /** Returns whether options can have parameter values that resemble an option, or whether such values should be rejected as unknown options. + * The default is {@code true}, so by default input like {@code -x=-unknown} is accepted if {@code -x} is an option that takes a String parameter. + *

This method only considers values that resemble options, as opposed to {@link #isAllowOptionsAsOptionParameters()}, which considers actual options of this command.

+ * @return {@code true} when options can have parameter values that resemble an option, {@code false} when such values should be rejected as unknown options + * @since 4.4 + * @see #isAllowOptionsAsOptionParameters() + * @see ParserSpec#unmatchedOptionsAllowedAsOptionParameters() + */ + public boolean isUnmatchedOptionsAllowedAsOptionParameters() { + return getCommandSpec().parser().unmatchedOptionsAllowedAsOptionParameters(); + } + + /** Sets whether options can have parameter values that resemble an option, or whether such values should be rejected as unknown options. + * The default is {@code true}, so by default + * input like {@code -x=-unknown} is accepted if {@code -x} is an option that takes a String parameter. + *

This method only considers values that resemble options, as opposed to {@link #setAllowOptionsAsOptionParameters(boolean)}, which considers actual options of this command.

+ *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting. When {@code true}, options can have parameter values that resemble an option, when {@code false}, such values are rejected as unknown options + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.4 + * @see #setAllowOptionsAsOptionParameters(boolean) + * @see ParserSpec#unmatchedOptionsAllowedAsOptionParameters(boolean) + */ + public CommandLine setUnmatchedOptionsAllowedAsOptionParameters(boolean newValue) { + getCommandSpec().parser().unmatchedOptionsAllowedAsOptionParameters(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setUnmatchedOptionsAllowedAsOptionParameters(newValue); + } + return this; + } + /** Returns whether arguments on the command line that resemble an option should be treated as positional parameters. + * The default is {@code false} and the parser behaviour depends on {@link #isUnmatchedArgumentsAllowed()}. + * @return {@code true} arguments on the command line that resemble an option should be treated as positional parameters, {@code false} otherwise + * @see #getUnmatchedArguments() + * @since 3.0 + */ + public boolean isUnmatchedOptionsArePositionalParams() { + return getCommandSpec().parser().unmatchedOptionsArePositionalParams(); + } + + /** Sets whether arguments on the command line that resemble an option should be treated as positional parameters. + * The default is {@code false}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting. When {@code true}, arguments on the command line that resemble an option should be treated as positional parameters. + * @return this {@code CommandLine} object, to allow method chaining + * @since 3.0 + * @see #getUnmatchedArguments() + * @see #isUnmatchedArgumentsAllowed + */ + public CommandLine setUnmatchedOptionsArePositionalParams(boolean newValue) { + getCommandSpec().parser().unmatchedOptionsArePositionalParams(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setUnmatchedOptionsArePositionalParams(newValue); + } + return this; + } + + /** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields. + * The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens. + * When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method. + * @return {@code true} if the end use may specify unmatched arguments on the command line, {@code false} otherwise + * @see #getUnmatchedArguments() + * @since 0.9.7 + */ + public boolean isUnmatchedArgumentsAllowed() { + return getCommandSpec().parser().unmatchedArgumentsAllowed(); + } + + /** Sets whether the end user may specify unmatched arguments on the command line without a {@link UnmatchedArgumentException} being thrown. + * The default is {@code false}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param newValue the new setting. When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method. + * @return this {@code CommandLine} object, to allow method chaining + * @since 0.9.7 + * @see #getUnmatchedArguments() + */ + public CommandLine setUnmatchedArgumentsAllowed(boolean newValue) { + getCommandSpec().parser().unmatchedArgumentsAllowed(newValue); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setUnmatchedArgumentsAllowed(newValue); + } + return this; + } + + /** Returns the list of unmatched command line arguments, if any. + * @return the list of unmatched command line arguments or an empty list + * @see #isUnmatchedArgumentsAllowed() + * @since 0.9.7 + */ + public List getUnmatchedArguments() { + return interpreter.parseResultBuilder == null ? Collections.emptyList() : UnmatchedArgumentException.stripErrorMessage(interpreter.parseResultBuilder.unmatched); + } + + /** + * Defines some exit codes used by acrostics as default return values from the {@link #execute(String...) execute} + * and {@link #executeHelpRequest(ParseResult) executeHelpRequest} methods. + *

Commands can override these defaults with annotations (e.g. {@code @Command(exitCodeOnInvalidInput = 64, exitCodeOnExecutionException = 70)} + * or programmatically (e.g. {@link CommandSpec#exitCodeOnInvalidInput(int)}).

+ *

Additionally, there are several mechanisms for commands to return custom exit codes. + * See the javadoc of the {@link #execute(String...) execute} method for details.

+ *

Standard Exit Codes

+ *

There are a few conventions, but there is no + * standard. The specific set of codes returned is unique to the program that sets it. + * Typically an exit code of zero indicates success, any non-zero exit code indicates failure. For reference, here are a few conventions:

+ * + *

Valid Ranges

+ *

Note that *nix shells may restrict exit codes to the 0-255 range, DOS seems to allow larger numbers. + * See this StackOverflow question.

+ * @since 4.0 */ + public static final class ExitCode { + /** Return value from the {@link #execute(String...) execute} and + * {@link #executeHelpRequest(ParseResult) executeHelpRequest} methods signifying successful termination. + *

The value of this constant is {@value}.

*/ + public static final int OK = 0; + /** Return value from the {@link #execute(String...) execute} method signifying internal software error: an exception occurred when invoking the Runnable, Callable or Method user object of a command.

The value of this constant is {@value}.

*/ + public static final int SOFTWARE = 1; + /** Return value from the {@link #execute(String...) execute} method signifying command line usage error: user input for the command was incorrect, e.g., the wrong number of arguments, a bad flag, a bad syntax in a parameter, or whatever.

The value of this constant is {@value}.

*/ + public static final int USAGE = 2; + private ExitCode() {} // don't instantiate + } + + /** {@code @Command}-annotated classes can implement this interface to specify an exit code that will be returned + * from the {@link #execute(String...) execute} method when the command is successfully invoked. + * + *

Example usage:

+ *
+     * @Command
+     * class MyCommand implements Runnable, IExitCodeGenerator {
+     *     public void run() { System.out.println("Hello"); }
+     *     public int getExitCode() { return 123; }
+     * }
+     * CommandLine cmd = new CommandLine(new MyCommand());
+     * int exitCode = cmd.execute(args);
+     * assert exitCode == 123;
+     * System.exit(exitCode);
+     * 
+ * @since 4.0 + */ + public interface IExitCodeGenerator { + /** Returns the exit code that should be returned from the {@link #execute(String...) execute} method. + * @return the exit code + */ + int getExitCode(); + } + /** Interface that provides the appropriate exit code that will be returned from the {@link #execute(String...) execute} + * method for an exception that occurred during parsing or while invoking the command's Runnable, Callable, or Method. + *

Example usage:

+ *
+     * @Command
+     * class FailingCommand implements Callable<Void> {
+     *     public Void call() throws IOException {
+     *         throw new IOException("error");
+     *     }
+     * }
+     * IExitCodeExceptionMapper mapper = new IExitCodeExceptionMapper() {
+     *     public int getExitCode(Throwable t) {
+     *         if (t instanceof IOException && "error".equals(t.getMessage())) {
+     *             return 123;
+     *         }
+     *         return 987;
+     *     }
+     * }
+     *
+     * CommandLine cmd = new CommandLine(new FailingCommand());
+     * cmd.setExitCodeExceptionMapper(mapper);
+     * int exitCode = cmd.execute(args);
+     * assert exitCode == 123;
+     * System.exit(exitCode);
+     * 
+ * @see #setExitCodeExceptionMapper(IExitCodeExceptionMapper) + * @since 4.0 + */ + public interface IExitCodeExceptionMapper { + /** Returns the exit code that should be returned from the {@link #execute(String...) execute} method. + * @param exception the exception that occurred during parsing or while invoking the command's Runnable, Callable, or Method. + * @return the exit code + */ + int getExitCode(Throwable exception); + } + private static int mappedExitCode(Throwable t, IExitCodeExceptionMapper mapper, int defaultExitCode) { + try { + return (mapper != null) ? mapper.getExitCode(t) : defaultExitCode; + } catch (Exception ex) { + ex.printStackTrace(); + return defaultExitCode; + } + } + + /** Returns the color scheme to use when printing help. + * The default value is the {@linkplain acrostics.CommandLine.Help#defaultColorScheme(CommandLine.Help.Ansi) default color scheme} with {@link Help.Ansi#AUTO Ansi.AUTO}. + * @see #execute(String...) + * @see #usage(PrintStream) + * @see #usage(PrintWriter) + * @see #getUsageMessage() + * @see Help#defaultColorScheme(CommandLine.Help.Ansi) + * @since 4.0 + */ + public Help.ColorScheme getColorScheme() { return colorScheme; } + + /** Sets the color scheme to use when printing help. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param colorScheme the new color scheme + * @see #execute(String...) + * @see #usage(PrintStream) + * @see #usage(PrintWriter) + * @see #getUsageMessage() + * @since 4.0 + */ + public CommandLine setColorScheme(Help.ColorScheme colorScheme) { + this.colorScheme = Assert.notNull(colorScheme, "colorScheme"); + for (CommandLine sub : getSubcommands().values()) { sub.setColorScheme(colorScheme); } + return this; + } + + /** Returns the writer used when printing user-requested usage help or version help during command {@linkplain #execute(String...) execution}. + * Defaults to a PrintWriter wrapper around {@code System.out} unless {@link #setOut(PrintWriter)} was called with a different writer. + *

This method is used by {@link #execute(String...)}. Custom {@link IExecutionStrategy IExecutionStrategy} implementations should also use this writer. + *

+ * By convention, when the user requests + * help with a {@code --help} or similar option, the usage help message is printed to the standard output stream so that it can be easily searched and paged.

+ * @since 4.0 */ + public PrintWriter getOut() { + if (out == null) { setOut(newPrintWriter(System.out, getStdoutEncoding())); } + return out; + } + + /** Sets the writer to use when printing user-requested usage help or version help during command {@linkplain #execute(String...) execution}. + *

This method is used by {@link #execute(String...)}. Custom {@link IExecutionStrategy IExecutionStrategy} implementations should also use this writer.

+ *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param out the new PrintWriter to use + * @return this CommandLine for method chaining + * @since 4.0 + */ + public CommandLine setOut(PrintWriter out) { + this.out = Assert.notNull(out, "out"); + for (CommandLine sub : getSubcommands().values()) { sub.setOut(out); } + return this; + } + + /** Returns the writer to use when printing diagnostic (error) messages during command {@linkplain #execute(String...) execution}. + * Defaults to a PrintWriter wrapper around {@code System.err}, unless {@link #setErr(PrintWriter)} was called with a different writer. + *

This method is used by {@link #execute(String...)}. + * {@link IParameterExceptionHandler IParameterExceptionHandler} and {@link IExecutionExceptionHandler IExecutionExceptionHandler} implementations + * should use this writer to print error messages (which may include a usage help message) when an unexpected error occurs.

+ * @since 4.0 */ + public PrintWriter getErr() { + if (err == null) { setErr(newPrintWriter(System.err, getStderrEncoding())); } + return err; + } + + /** Sets the writer to use when printing diagnostic (error) messages during command {@linkplain #execute(String...) execution}. + *

This method is used by {@link #execute(String...)}. + * {@link IParameterExceptionHandler IParameterExceptionHandler} and {@link IExecutionExceptionHandler IExecutionExceptionHandler} implementations + * should use this writer to print error messages (which may include a usage help message) when an unexpected error occurs.

+ *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param err the new PrintWriter to use + * @return this CommandLine for method chaining + * @since 4.0 */ + public CommandLine setErr(PrintWriter err) { + this.err = Assert.notNull(err, "err"); + for (CommandLine sub : getSubcommands().values()) { sub.setErr(err); } + return this; + } + + /** + * Returns the mapper that was set by the application to map from exceptions to exit codes, for use by the {@link #execute(String...) execute} method. + * @return the mapper that was {@linkplain #setExitCodeExceptionMapper(IExitCodeExceptionMapper) set}, or {@code null} if none was set + * @since 4.0 */ + public IExitCodeExceptionMapper getExitCodeExceptionMapper() { return exitCodeExceptionMapper; } + + /** Sets the mapper used by the {@link #execute(String...) execute} method to map exceptions to exit codes. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param exitCodeExceptionMapper the new value + * @return this CommandLine for method chaining + * @since 4.0 */ + public CommandLine setExitCodeExceptionMapper(IExitCodeExceptionMapper exitCodeExceptionMapper) { + this.exitCodeExceptionMapper = Assert.notNull(exitCodeExceptionMapper, "exitCodeExceptionMapper"); + for (CommandLine sub : getSubcommands().values()) { sub.setExitCodeExceptionMapper(exitCodeExceptionMapper); } + return this; + } + + /** Returns the execution strategy used by the {@link #execute(String...) execute} method to invoke + * the business logic on the user objects of this command and/or the user-specified subcommand(s). + * The default value is {@link RunLast RunLast}. + * @return the execution strategy to run the user-specified command + * @since 4.0 */ + public IExecutionStrategy getExecutionStrategy() { return executionStrategy; } + + /** Sets the execution strategy that the {@link #execute(String...) execute} method should use to invoke + * the business logic on the user objects of this command and/or the user-specified subcommand(s). + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param executionStrategy the new execution strategy to run the user-specified command + * @return this CommandLine for method chaining + * @since 4.0 */ + public CommandLine setExecutionStrategy(IExecutionStrategy executionStrategy) { + this.executionStrategy = Assert.notNull(executionStrategy, "executionStrategy"); + for (CommandLine sub : getSubcommands().values()) { sub.setExecutionStrategy(executionStrategy); } + return this; + } + + /** + * Returns the handler for dealing with invalid user input when the command is {@linkplain #execute(String...) executed}. + *

The default implementation prints an error message describing the problem, followed by either {@linkplain UnmatchedArgumentException#printSuggestions(PrintWriter) suggested alternatives} + * for mistyped options, or the full {@linkplain #usage(PrintWriter, Help.ColorScheme) usage} help message of the {@linkplain ParameterException#getCommandLine() problematic command}; + * it then delegates to the {@linkplain #getExitCodeExceptionMapper() exit code exception mapper} for an exit code, with + * {@link CommandSpec#exitCodeOnInvalidInput() exitCodeOnInvalidInput} as the default exit code.

+ *

+ * Alternatively, you can install a "short error message handler" like this: + *

+ *
+     * static class ShortErrorMessageHandler implements IParameterExceptionHandler {
+     *     public int handleParseException(ParameterException ex, String[] args) {
+     *         CommandLine cmd = ex.getCommandLine();
+     *         PrintWriter writer = cmd.getErr();
+     *
+     *         writer.println(ex.getMessage());
+     *         UnmatchedArgumentException.printSuggestions(ex, writer);
+     *         writer.print(cmd.getHelp().fullSynopsis());
+     *
+     *         CommandSpec spec = cmd.getCommandSpec();
+     *         writer.printf("Try '%s --help' for more information.%n", spec.qualifiedName());
+     *
+     *         return cmd.getExitCodeExceptionMapper() != null
+     *                     ? cmd.getExitCodeExceptionMapper().getExitCode(ex)
+     *                     : spec.exitCodeOnInvalidInput();
+     *     }
+     * }
+     * 
+ *

Install this error handler like this:

+ *
+     * new CommandLine(new MyApp())
+     *     .setParameterExceptionHandler(new ShortErrorMessageHandler())
+     *     .execute(args);
+     * 
+ * @return the handler for dealing with invalid user input + * @since 4.0 */ + public IParameterExceptionHandler getParameterExceptionHandler() { return parameterExceptionHandler; } + + /** + * Sets the handler for dealing with invalid user input when the command is {@linkplain #execute(String...) executed}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param parameterExceptionHandler the new handler for dealing with invalid user input + * @return this CommandLine for method chaining + * @see #getParameterExceptionHandler() an example short exception handler + * @since 4.0 */ + public CommandLine setParameterExceptionHandler(IParameterExceptionHandler parameterExceptionHandler) { + this.parameterExceptionHandler = Assert.notNull(parameterExceptionHandler, "parameterExceptionHandler"); + for (CommandLine sub : getSubcommands().values()) { sub.setParameterExceptionHandler(parameterExceptionHandler); } + return this; + } + + /** Returns the handler for dealing with exceptions that occurred in the {@code Callable}, {@code Runnable} or {@code Method} + * user object of a command when the command was {@linkplain #execute(String...) executed}. + *

The default implementation rethrows the specified exception.

+ * @return the handler for dealing with exceptions that occurred in the business logic when the {@link #execute(String...) execute} method was invoked. + * @since 4.0 */ + public IExecutionExceptionHandler getExecutionExceptionHandler() { return executionExceptionHandler; } + + /** + * Sets a custom handler for dealing with exceptions that occurred in the {@code Callable}, {@code Runnable} or {@code Method} + * user object of a command when the command was executed via the {@linkplain #execute(String...) execute} method. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param executionExceptionHandler the handler for dealing with exceptions that occurred in the business logic when the {@link #execute(String...) execute} method was invoked. + * @return this CommandLine for method chaining + * @since 4.0 */ + public CommandLine setExecutionExceptionHandler(IExecutionExceptionHandler executionExceptionHandler) { + this.executionExceptionHandler = Assert.notNull(executionExceptionHandler, "executionExceptionHandler"); + for (CommandLine sub : getSubcommands().values()) { sub.setExecutionExceptionHandler(executionExceptionHandler); } + return this; + } + + /** + *

+ * Convenience method that initializes the specified annotated object from the specified command line arguments. + *

+ * This is equivalent to + *

+     * new CommandLine(command).parseArgs(args);
+     * return command;
+     * 
+ *

All this method does is parse the arguments and populate the annotated fields and methods. + * The caller is responsible for catching any exceptions, handling requests for usage help + * or version information, and invoking the business logic. + * Applications may be interested in using the {@link #execute(String...)} method instead.

+ * + * @param command the object to initialize. This object contains fields annotated with + * {@code @Option} or {@code @Parameters}. + * @param args the command line arguments to parse + * @param the type of the annotated object + * @return the specified annotated object + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ParameterException if the specified command line arguments are invalid + * @see #execute(String...) + * @since 0.9.7 + */ + public static T populateCommand(T command, String... args) { + CommandLine cli = toCommandLine(command, new DefaultFactory()); + cli.parse(args); + return command; + } + + /** + *

+ * Convenience method that derives the command specification from the specified interface class, and returns an + * instance of the specified interface. The interface is expected to have annotated getter methods. Picocli will + * instantiate the interface and the getter methods will return the option and positional parameter values matched on the command line. + *

+ * This is equivalent to + *

+     * CommandLine cli = new CommandLine(spec);
+     * cli.parse(args);
+     * return cli.getCommand();
+     * 
+ *

All this method does is parse the arguments and return an instance whose annotated methods return the specified values. + * The caller is responsible for catching any exceptions, handling requests for usage help + * or version information, and invoking the business logic. + * Applications may be interested in using the {@link #execute(String...)} method instead.

+ * + * @param spec the interface that defines the command specification. This object contains getter methods annotated with + * {@code @Option} or {@code @Parameters}. + * @param args the command line arguments to parse + * @param the type of the annotated object + * @return an instance of the specified annotated interface + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ParameterException if the specified command line arguments are invalid + * @see #execute(String...) + * @since 3.1 + */ + public static T populateSpec(Class spec, String... args) { + CommandLine cli = toCommandLine(spec, new DefaultFactory()); + cli.parse(args); + return cli.getCommand(); + } + + /** Expands any {@linkplain CommandLine#isExpandAtFiles() @-files} in the specified command line arguments, then + * parses the arguments and returns a list of {@code CommandLine} objects representing the + * top-level command and any subcommands (if any) that were recognized and initialized during the parsing process. + *

+ * If parsing succeeds, the first element in the returned list is always {@code this CommandLine} object. The + * returned list may contain more elements if subcommands were {@linkplain #addSubcommand(String, Object) registered} + * and these subcommands were initialized by matching command line arguments. If parsing fails, a + * {@link ParameterException} is thrown. + *

+ *

All this method does is parse the arguments and populate the annotated fields and methods. + * The caller is responsible for catching any exceptions, handling requests for usage help + * or version information, and invoking the business logic. + * Applications may be interested in using the {@link #execute(String...)} method instead.

+ * + * @param args the command line arguments to parse + * @return a list with the top-level command and any subcommands initialized by this method + * @throws ParameterException if the specified command line arguments are invalid; use + * {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid + * @deprecated use {@link #parseArgs(String...)} instead + */ + @Deprecated public List parse(String... args) { + return interpreter.parse(args); + } + /** Expands any {@linkplain CommandLine#isExpandAtFiles() @-files} in the specified command line arguments, then + * parses the arguments and returns a {@code ParseResult} with the options, positional + * parameters, and subcommands (if any) that were recognized and initialized during the parsing process. + *

If parsing fails, a {@link ParameterException} is thrown.

+ *

All this method does is parse the arguments and populate the annotated fields and methods. + * The caller is responsible for catching any exceptions, handling requests for usage help + * or version information, and invoking the business logic. + * Applications may be interested in using the {@link #execute(String...)} method instead.

+ * + * @param args the command line arguments to parse + * @return a list with the top-level command and any subcommands initialized by this method + * @throws ParameterException if the specified command line arguments are invalid; use + * {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid + * @see #execute(String...) + */ + public ParseResult parseArgs(String... args) { + interpreter.parse(args); + return getParseResult(); + } + public ParseResult getParseResult() { return interpreter.parseResultBuilder == null ? null : interpreter.parseResultBuilder.build(); } + + /** Returns the result of calling the user object {@code Callable} or invoking the user object {@code Method} + * after parsing the user input, or {@code null} if this command has not been {@linkplain #execute(String...) executed} + * or if this {@code CommandLine} is for a subcommand that was not specified by the end user on the command line. + *

Implementation note:

+ *

It is the responsibility of the {@link IExecutionStrategy IExecutionStrategy} to set this value.

+ * @param type of the result value + * @return the result of the user object {@code Callable} or {@code Method} (may be {@code null}), or {@code null} if this (sub)command was not executed + * @since 4.0 + */ + @SuppressWarnings("unchecked") public T getExecutionResult() { return (T) executionResult; } + + /** Sets the result of calling the business logic on the command's user object. + * @param result the business logic result, may be {@code null} + * @see #execute(String...) + * @see IExecutionStrategy + * @since 4.0 + */ + public void setExecutionResult(Object result) { executionResult = result; } + + /** Clears the {@linkplain #getExecutionResult() execution result} of a previous invocation from this {@code CommandLine} and all subcommands. + * @since 4.0 */ + public void clearExecutionResults() { + executionResult = null; + for (CommandLine sub : getSubcommands().values()) { sub.clearExecutionResults(); } + } + /** + * Represents a function that can process a List of {@code CommandLine} objects resulting from successfully + * {@linkplain #parse(String...) parsing} the command line arguments. This is a + * functional interface + * whose functional method is {@link #handleParseResult(List, PrintStream, CommandLine.Help.Ansi)}. + *

+ * Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler} + * methods to take some next step after the command line was successfully parsed. + *

+ * @see RunFirst + * @see RunLast + * @see RunAll + * @deprecated Use {@link IExecutionStrategy} instead. + * @since 2.0 */ + @Deprecated public interface IParseResultHandler { + /** Processes a List of {@code CommandLine} objects resulting from successfully + * {@linkplain #parse(String...) parsing} the command line arguments and optionally returns a list of results. + * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments + * @param out the {@code PrintStream} to print help to if requested + * @param ansi for printing help messages using ANSI styles and colors + * @return a list of results, or an empty list if there are no results + * @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions} + * thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + */ + List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi) throws ExecutionException; + } + + /** + * Represents a function that can process the {@code ParseResult} object resulting from successfully + * {@linkplain #parseArgs(String...) parsing} the command line arguments. This is a + * functional interface + * whose functional method is {@link IParseResultHandler2#handleParseResult(CommandLine.ParseResult)}. + *

+ * Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) CommandLine::parseWithHandlers} + * methods to take some next step after the command line was successfully parsed. + *

+ * This interface replaces the {@link IParseResultHandler} interface; it takes the parse result as a {@code ParseResult} + * object instead of a List of {@code CommandLine} objects, and it has the freedom to select the {@link Help.Ansi} style + * to use and what {@code PrintStreams} to print to. + *

+ * @param the return type of this handler + * @see RunFirst + * @see RunLast + * @see RunAll + * @deprecated use {@link IExecutionStrategy} instead, see {@link #execute(String...)} + * @since 3.0 */ + @Deprecated public interface IParseResultHandler2 { + /** Processes the {@code ParseResult} object resulting from successfully + * {@linkplain CommandLine#parseArgs(String...) parsing} the command line arguments and returns a return value. + * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments + * @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions} + * thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + */ + R handleParseResult(ParseResult parseResult) throws ExecutionException; + } + + /** + * Implementations are responsible for "executing" the user input and returning an exit code. + * The {@link #execute(String...)} method delegates to a {@linkplain #setExecutionStrategy(IExecutionStrategy) configured} execution strategy. + *

Implementation Requirements:

+ *

Implementers responsibilities are:

+ *
    + *
  • From the {@code ParseResult}, select which {@code CommandSpec} should be executed. This is especially important for commands that have subcommands.
  • + *
  • "Execute" the selected {@code CommandSpec}. Often this means invoking a method on the spec's {@linkplain CommandSpec#userObject() user object}.
  • + *
  • Call {@link CommandLine#setExecutionResult(Object) setExecutionResult} to make the return value of that method invocation available to the application
  • + *
  • Return an exit code. Common sources of exit values are the invoked method's return value, or the user object if it implements {@link IExitCodeGenerator}.
  • + *
+ *

Implementors that need to print messages to the console should use the {@linkplain #getOut() output} and {@linkplain #getErr() error} PrintWriters, + * and the {@linkplain #getColorScheme() color scheme} from the CommandLine object obtained from ParseResult's CommandSpec.

+ *

API Note:

+ *

This interface supersedes {@link IParseResultHandler2}.

+ * @since 4.0 */ + public interface IExecutionStrategy { + /** + * "Executes" the user input and returns an exit code. + * Execution often means invoking a method on the selected CommandSpec's {@linkplain CommandSpec#userObject() user object}, + * and making the return value of that invocation available via {@link CommandLine#setExecutionResult(Object) setExecutionResult}. + * @param parseResult the parse result from which to select one or more {@code CommandSpec} instances to execute. + * @return an exit code + * @throws ParameterException if the invoked method on the CommandSpec's user object threw a ParameterException to signify invalid user input. + * @throws ExecutionException if any problem occurred while executing the command. Any exceptions (other than ParameterException) should be wrapped in a ExecutionException and not thrown as is. + */ + int execute(ParseResult parseResult) throws ExecutionException, ParameterException; + } + + /** + * Represents a function that can handle a {@code ParameterException} that occurred while + * {@linkplain #parse(String...) parsing} the command line arguments. This is a + * functional interface + * whose functional method is {@link #handleException(CommandLine.ParameterException, PrintStream, CommandLine.Help.Ansi, String...)}. + *

+ * Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandlers} + * methods to handle situations when the command line could not be parsed. + *

+ * @deprecated see {@link #execute(String...)}, {@link IParameterExceptionHandler} and {@link IExecutionExceptionHandler} + * @since 2.0 */ + @Deprecated public interface IExceptionHandler { + /** Handles a {@code ParameterException} that occurred while {@linkplain #parse(String...) parsing} the command + * line arguments and optionally returns a list of results. + * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments, + * and the CommandLine representing the command or subcommand whose input was invalid + * @param out the {@code PrintStream} to print help to if requested + * @param ansi for printing help messages using ANSI styles and colors + * @param args the command line arguments that could not be parsed + * @return a list of results, or an empty list if there are no results + */ + List handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args); + } + /** + * Classes implementing this interface know how to handle {@code ParameterExceptions} (usually from invalid user input) + * and {@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command. + *

+ * Implementations of this interface can be passed to the + * {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) CommandLine::parseWithHandlers} method. + *

+ * This interface replaces the {@link IParseResultHandler} interface. + *

+ * @param the return type of this handler + * @see DefaultExceptionHandler + * @deprecated see {@link #execute(String...)}, {@link IParameterExceptionHandler} and {@link IExecutionExceptionHandler} + * @since 3.0 */ + @Deprecated public interface IExceptionHandler2 { + /** Handles a {@code ParameterException} that occurred while {@linkplain #parseArgs(String...) parsing} the command + * line arguments and optionally returns a list of results. + * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments, + * and the CommandLine representing the command or subcommand whose input was invalid + * @param args the command line arguments that could not be parsed + * @return an object resulting from handling the exception + */ + R handleParseException(ParameterException ex, String[] args); + /** Handles a {@code ExecutionException} that occurred while executing the {@code Runnable} or + * {@code Callable} command and optionally returns a list of results. + * @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or + * {@code Callable} command, and the CommandLine representing the command or subcommand that was being executed + * @param parseResult the result of parsing the command line arguments + * @return an object resulting from handling the exception + */ + R handleExecutionException(ExecutionException ex, ParseResult parseResult); + } + + /** Classes implementing this interface know how to handle {@code ParameterExceptions} (usually from invalid user input). + *

Implementation Requirements:

+ *

Implementors that need to print messages to the console should use the {@linkplain #getOut() output} and {@linkplain #getErr() error} PrintWriters, + * and the {@linkplain #getColorScheme() color scheme} from the CommandLine object obtained from the exception.

+ *

Implementation Note:

+ *

See {@link #getParameterExceptionHandler()} for a description of the default handler.

+ *

API Note:

+ *

This interface supersedes {@link IExceptionHandler2}.

+ * @see CommandLine#setParameterExceptionHandler(IParameterExceptionHandler) + * @since 4.0 + */ + public interface IParameterExceptionHandler { + /** Handles a {@code ParameterException} that occurred while {@linkplain #parseArgs(String...) parsing} the command + * line arguments and returns an exit code suitable for returning from {@link #execute(String...)}. + * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments, + * and the CommandLine representing the command or subcommand whose input was invalid + * @param args the command line arguments that could not be parsed + * @return an exit code + */ + int handleParseException(ParameterException ex, String[] args) throws Exception; + } + /** + * Classes implementing this interface know how to handle Exceptions that occurred while executing the {@code Runnable}, {@code Callable} or {@code Method} user object of the command. + *

Implementation Requirements:

+ *

Implementors that need to print messages to the console should use the {@linkplain #getOut() output} and {@linkplain #getErr() error} PrintWriters, + * and the {@linkplain #getColorScheme() color scheme} from the CommandLine object obtained from the exception.

+ *

API Note:

+ *

This interface supersedes {@link IExceptionHandler2}.

+ *

Example usage:

+ *
+     * IExecutionExceptionHandler errorHandler = new IExecutionExceptionHandler() {
+     *     public int handleExecutionException(Exception ex,
+     *                                         CommandLine commandLine,
+     *                                         ParseResult parseResult) {
+     *         //ex.printStackTrace(); // no stack trace
+     *         commandLine.getErr().println(ex.getMessage());
+     *         commandLine.usage(commandLine.getErr());
+     *         return commandLine.getCommandSpec().exitCodeOnExecutionException();
+     *     }
+     * };
+     * int exitCode = new CommandLine(new App())
+     *         .setExecutionExceptionHandler(errorHandler)
+     *         .execute(args);
+     * 
+ * @see CommandLine#setExecutionExceptionHandler(IExecutionExceptionHandler) + * @since 4.0 + */ + public interface IExecutionExceptionHandler { + /** Handles an {@code Exception} that occurred while executing the {@code Runnable} or + * {@code Callable} command and returns an exit code suitable for returning from {@link #execute(String...)}. + * @param ex the Exception thrown by the {@code Runnable}, {@code Callable} or {@code Method} user object of the command + * @param commandLine the CommandLine representing the command or subcommand where the exception occurred + * @param fullParseResult the result of parsing the command line arguments. + * This is the ParseResult of the top-level command. + * Note that if the exception occurred in a subcommand, you may want to inspect the ParseResult of + * the subcommand that threw the exception, which can be obtained by calling {@code commandLine.getParseResult()} + * on the CommandLine object passed to this method. + * @return an exit code + */ + int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult fullParseResult) throws Exception; + } + + /** Abstract superclass for {@link IParseResultHandler2} and {@link IExceptionHandler2} implementations. + *

Note that {@code AbstractHandler} is a generic type. This, along with the abstract {@code self} method, + * allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:

+ *
{@code
+     * class MyResultHandler extends AbstractHandler implements IParseResultHandler2 {
+     *
+     *     public MyReturnType handleParseResult(ParseResult parseResult) { ... }
+     *
+     *     protected MyResultHandler self() { return this; }
+     * }
+     * }
+ * @param the return type of this handler + * @param The type of the handler subclass; for fluent API method chaining + * @deprecated see {@link #execute(String...)} + * @since 3.0 */ + @Deprecated public static abstract class AbstractHandler> { + private Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO); + private Integer exitCode; + private PrintStream out = System.out; + private PrintStream err = System.err; + + /** Returns the stream to print command output to. Defaults to {@code System.out}, unless {@link #useOut(PrintStream)} + * was called with a different stream. + *

{@code IParseResultHandler2} implementations should use this stream. + * By convention, when the user requests + * help with a {@code --help} or similar option, the usage help message is printed to the standard output stream so that it can be easily searched and paged.

*/ + public PrintStream out() { return out; } + /** Returns the stream to print diagnostic messages to. Defaults to {@code System.err}, unless {@link #useErr(PrintStream)} + * was called with a different stream.

{@code IExceptionHandler2} implementations should use this stream to print error + * messages (which may include a usage help message) when an unexpected error occurs.

*/ + public PrintStream err() { return err; } + /** Returns the ANSI style to use. Defaults to {@code Help.Ansi.AUTO}, unless {@link #useAnsi(CommandLine.Help.Ansi)} was called with a different setting. + * @deprecated use {@link #colorScheme()} instead */ + @Deprecated public Help.Ansi ansi() { return colorScheme.ansi(); } + /** Returns the ColorScheme to use. Defaults to {@code Help#defaultColorScheme(Help.Ansi.AUTO)}. + * @since 4.0*/ + public Help.ColorScheme colorScheme() { return colorScheme; } + /** Returns the exit code to use as the termination status, or {@code null} (the default) if the handler should + * not call {@link System#exit(int)} after processing completes. + * @see #andExit(int) */ + public Integer exitCode() { return exitCode; } + /** Returns {@code true} if an exit code was set with {@link #andExit(int)}, or {@code false} (the default) if + * the handler should not call {@link System#exit(int)} after processing completes. */ + public boolean hasExitCode() { return exitCode != null; } + + /** Convenience method for subclasses that returns the specified result object if no exit code was set, + * or otherwise, if an exit code {@linkplain #andExit(int) was set}, calls {@code System.exit} with the configured + * exit code to terminate the currently running Java virtual machine. */ + protected R returnResultOrExit(R result) { + if (hasExitCode()) { exit(exitCode()); } + return result; + } + + /** Convenience method for subclasses that throws the specified ExecutionException if no exit code was set, + * or otherwise, if an exit code {@linkplain #andExit(int) was set}, prints the stacktrace of the specified exception + * to the diagnostic error stream and calls {@code System.exit} with the configured + * exit code to terminate the currently running Java virtual machine. */ + protected R throwOrExit(ExecutionException ex) { + if (hasExitCode()) { + ex.printStackTrace(this.err()); + exit(exitCode()); + return null; + } + throw ex; + } + /** Calls {@code System.exit(int)} with the specified exit code. */ + protected void exit(int exitCode) { System.exit(exitCode); } + + /** Returns {@code this} to allow method chaining when calling the setters for a fluent API. */ + protected abstract T self(); + + /** Sets the stream to print command output to. + * @deprecated use {@link CommandLine#setOut(PrintWriter)} and {@link CommandLine#execute(String...)} instead */ + @Deprecated public T useOut(PrintStream out) { this.out = Assert.notNull(out, "out"); return self(); } + /** Sets the stream to print diagnostic messages to. + * @deprecated use {@link CommandLine#setErr(PrintWriter)} and {@link CommandLine#execute(String...)} instead */ + @Deprecated public T useErr(PrintStream err) { this.err = Assert.notNull(err, "err"); return self(); } + /** Sets the ANSI style to use and resets the color scheme to the default. + * @deprecated use {@link CommandLine#setColorScheme(Help.ColorScheme)} and {@link CommandLine#execute(String...)} instead + * @see #ansi() */ + @Deprecated public T useAnsi(Help.Ansi ansi) { this.colorScheme = Help.defaultColorScheme(Assert.notNull(ansi, "ansi")); return self(); } + /** Indicates that the handler should call {@link System#exit(int)} after processing completes and sets the exit code to use as the termination status. + * @deprecated use {@link CommandLine#execute(String...)} instead, and call {@code System.exit()} in the application. */ + @Deprecated public T andExit(int exitCode) { this.exitCode = exitCode; return self(); } + } + + /** + * Default exception handler that handles invalid user input by printing the exception message, followed by the usage + * message for the command or subcommand whose input was invalid. + *

{@code ParameterExceptions} (invalid user input) is handled like this:

+ *
+     *     err().println(paramException.getMessage());
+     *     paramException.getCommandLine().usage(err(), ansi());
+     *     if (hasExitCode()) System.exit(exitCode()); else return returnValue;
+     * 
+ *

{@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command are simply rethrown and not handled.

+ * @deprecated see {@link #execute(String...)}, {@link #getParameterExceptionHandler()} and {@link #getExecutionExceptionHandler()} + * @since 2.0 */ + @Deprecated public static class DefaultExceptionHandler extends AbstractHandler> implements IExceptionHandler, IExceptionHandler2 { + public List handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args) { + internalHandleParseException(ex, newPrintWriter(out, getStdoutEncoding()), Help.defaultColorScheme(ansi)); return Collections.emptyList(); } + + /** Prints the message of the specified exception, followed by the usage message for the command or subcommand + * whose input was invalid, to the stream returned by {@link #err()}. + * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments, + * and the CommandLine representing the command or subcommand whose input was invalid + * @param args the command line arguments that could not be parsed + * @return the empty list + * @since 3.0 */ + public R handleParseException(ParameterException ex, String[] args) { + internalHandleParseException(ex, newPrintWriter(err(), getStderrEncoding()), colorScheme()); return returnResultOrExit(null); } + + static void internalHandleParseException(ParameterException ex, PrintWriter writer, Help.ColorScheme colorScheme) { + writer.println(colorScheme.errorText(ex.getMessage())); + if (!UnmatchedArgumentException.printSuggestions(ex, writer)) { + ex.getCommandLine().usage(writer, colorScheme); + } + Tracer tracer = CommandLine.tracer(); + if (tracer.isDebug()) { // #956 show error details if DEBUG is enabled + ex.printStackTrace(tracer.stream); + } + } + /** This implementation always simply rethrows the specified exception. + * @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or {@code Callable} command + * @param parseResult the result of parsing the command line arguments + * @return nothing: this method always rethrows the specified exception + * @throws ExecutionException always rethrows the specified exception + * @since 3.0 */ + public R handleExecutionException(ExecutionException ex, ParseResult parseResult) { return throwOrExit(ex); } + + @Override protected DefaultExceptionHandler self() { return this; } + } + /** Convenience method that returns {@code new DefaultExceptionHandler>()}. */ + public static DefaultExceptionHandler> defaultExceptionHandler() { return new DefaultExceptionHandler>(); } + + /** @deprecated use {@link #printHelpIfRequested(ParseResult)} instead + * @since 2.0 */ + @Deprecated public static boolean printHelpIfRequested(List parsedCommands, PrintStream out, Help.Ansi ansi) { + return printHelpIfRequested(parsedCommands, out, out, ansi); + } + /** + * Delegates to {@link #executeHelpRequest(ParseResult)}. + * @param parseResult contains the {@code CommandLine} objects found during parsing; check these to see if help was requested + * @return {@code true} if help was printed, {@code false} otherwise + * @since 3.0 */ + public static boolean printHelpIfRequested(ParseResult parseResult) { + return executeHelpRequest(parseResult) != null; + } + /** + * Delegates to the implementation of {@link #executeHelpRequest(ParseResult)}. + * @deprecated use {@link #executeHelpRequest(ParseResult)} instead + * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested + * @param out the {@code PrintStream} to print help to if requested + * @param err the error string to print diagnostic messages to, in addition to the output from the exception handler + * @param ansi for printing help messages using ANSI styles and colors + * @return {@code true} if help was printed, {@code false} otherwise + * @since 3.0 */ + @Deprecated public static boolean printHelpIfRequested(List parsedCommands, PrintStream out, PrintStream err, Help.Ansi ansi) { + return printHelpIfRequested(parsedCommands, out, err, Help.defaultColorScheme(ansi)); + } + /** + * Delegates to the implementation of {@link #executeHelpRequest(ParseResult)}. + * @deprecated use {@link #executeHelpRequest(ParseResult)} instead + * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested + * @param out the {@code PrintStream} to print help to if requested + * @param err the error string to print diagnostic messages to, in addition to the output from the exception handler + * @param colorScheme for printing help messages using ANSI styles and colors + * @return {@code true} if help was printed, {@code false} otherwise + * @since 3.6 */ + @Deprecated public static boolean printHelpIfRequested(List parsedCommands, PrintStream out, PrintStream err, Help.ColorScheme colorScheme) { + // for backwards compatibility + for (CommandLine cmd : parsedCommands) { cmd.setOut(newPrintWriter(out, getStdoutEncoding())).setErr(newPrintWriter(err, getStderrEncoding())).setColorScheme(colorScheme); } + return executeHelpRequest(parsedCommands) != null; + } + + /** + * Helper method that may be useful when processing the {@code ParseResult} that results from successfully + * {@linkplain #parseArgs(String...) parsing} command line arguments. This method prints out + * {@linkplain #usage(PrintWriter, Help.ColorScheme) usage help} to the {@linkplain CommandLine#getOut() configured output writer} + * if {@linkplain #isUsageHelpRequested() requested} or {@linkplain #printVersionHelp(PrintWriter, Help.Ansi, Object...) version help} + * to the {@linkplain CommandLine#getOut() configured output writer} if {@linkplain #isVersionHelpRequested() requested} + * and returns {@link CommandSpec#exitCodeOnUsageHelp()} or {@link CommandSpec#exitCodeOnVersionHelp()}, respectively. + * If the command is a {@link Command#helpCommand()} and {@code runnable} or {@code callable}, + * that command is executed and this method returns {@link CommandSpec#exitCodeOnUsageHelp()}. + * Otherwise, if none of the specified {@code CommandLine} objects have help requested, + * this method returns {@code null}.

+ * Note that this method only looks at the {@link Option#usageHelp() usageHelp} and + * {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored. + *

Implementation note:

+ * When an error occurs while processing the help request, it is recommended custom Help commands throw a + * {@link ParameterException} with a reference to the parent command. This will print the error message and the + * usage for the parent command, and will use the exit code of the exception handler if one was set. + *

+ * @param parseResult contains the {@code CommandLine} objects found during parsing; check these to see if help was requested + * @return {@link CommandSpec#exitCodeOnUsageHelp()} if usage help was requested, + * {@link CommandSpec#exitCodeOnVersionHelp()} if version help was requested, and {@code null} otherwise + * @see IHelpCommandInitializable2 + * @since 4.0 */ + public static Integer executeHelpRequest(ParseResult parseResult) { + return executeHelpRequest(parseResult.asCommandLineList()); + } + /** @since 4.0 */ + static Integer executeHelpRequest(List parsedCommands) { + Tracer t = CommandLine.tracer(); + for (CommandLine parsed : parsedCommands) { + Help.ColorScheme colorScheme = parsed.getColorScheme(); + PrintWriter out = parsed.getOut(); + if (parsed.isUsageHelpRequested()) { + t.debug("Printing usage help for '%s' as requested.", parsed.commandSpec.qualifiedName()); + parsed.usage(out, colorScheme); + return parsed.getCommandSpec().exitCodeOnUsageHelp(); + } else if (parsed.isVersionHelpRequested()) { + t.debug("Printing version info for '%s' as requested.", parsed.commandSpec.qualifiedName()); + parsed.printVersionHelp(out, colorScheme.ansi); + return parsed.getCommandSpec().exitCodeOnVersionHelp(); + } else if (parsed.getCommandSpec().helpCommand()) { + String fullName = parsed.commandSpec.qualifiedName(); + PrintWriter err = parsed.getErr(); + if (((Object) parsed.getCommand()) instanceof IHelpCommandInitializable2) { + t.debug("Initializing helpCommand '%s' (IHelpCommandInitializable2::init)...", fullName); + ((IHelpCommandInitializable2) parsed.getCommand()).init(parsed, colorScheme, out, err); + } else if (((Object) parsed.getCommand()) instanceof IHelpCommandInitializable) { + t.debug("Initializing helpCommand '%s' (IHelpCommandInitializable::init)...", fullName); + ((IHelpCommandInitializable) parsed.getCommand()).init(parsed, colorScheme.ansi, System.out, System.err); + } else { + t.debug("helpCommand '%s' does not implement IHelpCommandInitializable2 or IHelpCommandInitializable...", fullName); + } + t.debug("Executing helpCommand '%s'...", fullName); + executeUserObject(parsed, new ArrayList()); + return parsed.getCommandSpec().exitCodeOnUsageHelp(); + } + } + t.debug("Help was not requested. Continuing to process ParseResult..."); + return null; + } + private static List executeUserObject(CommandLine parsed, List executionResultList) { + Tracer tracer = CommandLine.tracer(); + + Object command = parsed.getCommand(); + if (command instanceof Runnable) { + try { + tracer.debug("Invoking Runnable::run on user object %s@%s...", command.getClass().getName(), Integer.toHexString(command.hashCode())); + ((Runnable) command).run(); + parsed.setExecutionResult(null); // 4.0 + executionResultList.add(null); // for compatibility with acrostics 2.x + return executionResultList; + } catch (ParameterException ex) { + throw ex; + } catch (ExecutionException ex) { + throw ex; + } catch (Exception ex) { + throw new ExecutionException(parsed, "Error while running command (" + command + "): " + ex, ex); + } + } else if (command instanceof Callable) { + try { + tracer.debug("Invoking Callable::call on user object %s@%s...", command.getClass().getName(), Integer.toHexString(command.hashCode())); + @SuppressWarnings("unchecked") Callable callable = (Callable) command; + Object executionResult = callable.call(); + parsed.setExecutionResult(executionResult); + executionResultList.add(executionResult); + return executionResultList; + } catch (ParameterException ex) { + throw ex; + } catch (ExecutionException ex) { + throw ex; + } catch (Exception ex) { + throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + ex, ex); + } + } else if (command instanceof Method) { + try { + Method method = (Method) command; + Object[] parsedArgs = parsed.getCommandSpec().commandMethodParamValues(); + Object executionResult; + if (Modifier.isStatic(method.getModifiers())) { + tracer.debug("Invoking static method %s with parameters %s", method, Arrays.toString(parsedArgs)); + executionResult = method.invoke(null, parsedArgs); // invoke static method + } else { + Object instance = (parsed.getCommandSpec().parent() != null) + ? parsed.getCommandSpec().parent().userObject() + : parsed.factory.create(method.getDeclaringClass()); + tracer.debug("Invoking method %s on %s@%s with parameters %s", + method, instance.getClass().getName(), Integer.toHexString(instance.hashCode()), Arrays.toString(parsedArgs)); + executionResult = method.invoke(instance, parsedArgs); + } + parsed.setExecutionResult(executionResult); + executionResultList.add(executionResult); + return executionResultList; + } catch (InvocationTargetException ex) { + Throwable t = ex.getTargetException(); + if (t instanceof ParameterException) { + throw (ParameterException) t; + } else if (t instanceof ExecutionException) { + throw (ExecutionException) t; + } else { + throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + t, t); + } + } catch (Exception ex) { + throw new ExecutionException(parsed, "Unhandled error while calling command (" + command + "): " + ex, ex); + } + } + if (parsed.getSubcommands().isEmpty()) { + throw new ExecutionException(parsed, "Parsed command (" + command + ") is not a Method, Runnable or Callable"); + } else { + throw new ParameterException(parsed, "Missing required subcommand"); + } + } + + /** + * Convenience method to allow command line application authors to avoid some boilerplate code in their application. + * To use this method, the annotated object that this {@code CommandLine} is constructed with needs to + * either implement {@link Runnable}, {@link Callable}, or be a {@code Method} object. + * See {@link #getCommandMethods(Class, String) getCommandMethods} for a convenient way to obtain a command {@code Method}. + *

This method replaces the {@link #run(Runnable, String...) run}, {@link #call(Callable, String...) call} + * and {@link #invoke(String, Class, String...) invoke} convenience methods that were available with previous versions of acrostics. + *

+ * Exit Code + *

+ * This method returns an exit code that applications can use to call {@code System.exit}. + * (The return value of the {@code Callable} or {@code Method} can still be obtained via {@link #getExecutionResult() getExecutionResult}.) + * If the user object {@code Callable} or {@code Method} returns an {@code int} or {@code Integer}, + * this will be used as the exit code. Additionally, if the user object implements {@link CommandLine.IExitCodeGenerator IExitCodeGenerator}, + * an exit code is obtained by calling its {@code getExitCode()} method (after invoking the user object). + *

+ * In the case of multiple exit codes the highest value will be used (or if all values are negative, the lowest value will be used). + *

+ * Exception Handling + *

+ * This method never throws an exception. + *

+ * If the user specified invalid input, the {@linkplain #getParameterExceptionHandler() parameter exception handler} is invoked. + * By default this prints an error message and the usage help message, and returns an exit code. + *

+ * If an exception occurred while the user object {@code Runnable}, {@code Callable}, or {@code Method} + * was invoked, this exception is caught and passed to the {@linkplain #getExecutionExceptionHandler() execution exception handler}. + * The default {@code IExecutionExceptionHandler} will rethrow this Exception. + *

+ * Any exception thrown from the {@code IParameterExceptionHandler} or {@code IExecutionExceptionHandler} is caught, + * it stacktrace is printed and is mapped to an exit code, using the following logic: + *

+ * If an {@link CommandLine.IExitCodeExceptionMapper IExitCodeExceptionMapper} is {@linkplain #setExitCodeExceptionMapper(IExitCodeExceptionMapper) configured}, + * this mapper is used to determine the exit code based on the exception. + *

+ * If an {@code IExitCodeExceptionMapper} is not set, by default this method will return the {@code @Command} annotation's + * {@link Command#exitCodeOnInvalidInput() exitCodeOnInvalidInput} or {@link Command#exitCodeOnExecutionException() exitCodeOnExecutionException} value, respectively. + *

Example Usage:

+ *
+     * @Command
+     * class MyCommand implements Callable<Integer> {
+     *     public Integer call() { return 123; }
+     * }
+     * CommandLine cmd = new CommandLine(new MyCommand());
+     * int exitCode = cmd.execute(args);
+     * assert exitCode == 123;
+     * System.exit(exitCode);
+     * 
+ *

Since {@code execute} is an instance method, not a static method, applications can do configuration before invoking the command. For example:

+ *
{@code
+     * CommandLine cmd = new CommandLine(new MyCallable())
+     *         .setCaseInsensitiveEnumValuesAllowed(true) // configure a non-default parser option
+     *         .setOut(myOutWriter()) // configure an alternative to System.out
+     *         .setErr(myErrWriter()) // configure an alternative to System.err
+     *         .setColorScheme(myColorScheme()); // configure a custom color scheme
+     * int exitCode = cmd.execute(args);
+     * System.exit(exitCode);
+     * }
+ *

+ * If the specified command has subcommands, the {@linkplain RunLast last} subcommand specified on the + * command line is executed. This can be configured by setting the {@linkplain #setExecutionStrategy(IExecutionStrategy) execution strategy}. + * Built-in alternatives are executing the {@linkplain RunFirst first} subcommand, or executing {@linkplain RunAll all} specified subcommands. + *

+ * @param args the command line arguments to parse + * @return the exit code + * @see ExitCode + * @see IExitCodeGenerator + * @see #getExecutionResult() + * @see #getExecutionStrategy() + * @see #getParameterExceptionHandler() + * @see #getExecutionExceptionHandler() + * @see #getExitCodeExceptionMapper() + * @since 4.0 + */ + public int execute(String... args) { + ParseResult[] parseResult = new ParseResult[1]; + clearExecutionResults(); + try { + parseResult[0] = parseArgs(args); + return enrichForBackwardsCompatibility(getExecutionStrategy()).execute(parseResult[0]); + } catch (ParameterException ex) { + try { + return getParameterExceptionHandler().handleParseException(ex, args); + } catch (Exception ex2) { + return handleUnhandled(ex2, ex.getCommandLine(), ex.getCommandLine().getCommandSpec().exitCodeOnInvalidInput()); + } + } catch (ExecutionException ex) { + try { + Exception cause = ex.getCause() instanceof Exception ? (Exception) ex.getCause() : ex; + return getExecutionExceptionHandler().handleExecutionException(cause, ex.getCommandLine(), parseResult[0]); + } catch (Exception ex2) { + return handleUnhandled(ex2, ex.getCommandLine(), ex.getCommandLine().getCommandSpec().exitCodeOnExecutionException()); + } + } catch (Exception ex) { + return handleUnhandled(ex, this, getCommandSpec().exitCodeOnExecutionException()); + } + } + private static int handleUnhandled(Exception ex, CommandLine cmd, int defaultExitCode) { + cmd.getErr().print(throwableToColorString(ex, cmd.getColorScheme())); + cmd.getErr().flush(); + return mappedExitCode(ex, cmd.getExitCodeExceptionMapper(), defaultExitCode); + } + + /** + * Convert a {@code Throwable} to a {@code String} , with message and stack traces extracted and colored + * according to {@code ColorScheme}. + * @param t the {@code Throwable} to be converted + * @param existingColorScheme the {@code ColorScheme} to use + * @return converted and colored {@code String} + */ + private static String throwableToColorString(Throwable t, Help.ColorScheme existingColorScheme) { + Help.ColorScheme colorScheme = new Help.ColorScheme.Builder(existingColorScheme).applySystemProperties().build(); + StringWriter stringWriter = new ColoredStackTraceWriter(colorScheme); + t.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); + } + + /** + * Extends StringWriter to use ColorScheme. Allows separating + * exception messages from stack traces by intercepting write method. + */ + static class ColoredStackTraceWriter extends StringWriter { + Help.ColorScheme colorScheme; + + public ColoredStackTraceWriter(Help.ColorScheme colorScheme) { this.colorScheme = colorScheme; } + + @Override + public void write(String str, int off, int len) { + List styles = str.startsWith("\t") ? colorScheme.stackTraceStyles() : colorScheme.errorStyles(); + super.write(colorScheme.apply(str.substring(off, len), styles).toString()); + } + } + + private T enrichForBackwardsCompatibility(T obj) { + // in case the IExecutionStrategy is a built-in like RunLast, + // and the application called #useOut, #useErr or #useAnsi on it + if (obj instanceof AbstractHandler) { + AbstractHandler handler = (AbstractHandler) obj; + if (handler.out() != System.out) { setOut(newPrintWriter(handler.out(), getStdoutEncoding())); } + if (handler.err() != System.err) { setErr(newPrintWriter(handler.err(), getStderrEncoding())); } + if (handler.ansi() != Help.Ansi.AUTO) { setColorScheme(handler.colorScheme()); } + } + return obj; + } + /** Command line parse result handler that returns a value. This handler prints help if requested, and otherwise calls + * {@link #handle(CommandLine.ParseResult)} with the parse result. Facilitates implementation of the {@link IParseResultHandler2} interface. + *

Note that {@code AbstractParseResultHandler} is a generic type. This, along with the abstract {@code self} method, + * allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:

+ *
{@code
+     * class MyResultHandler extends AbstractParseResultHandler {
+     *
+     *     protected MyReturnType handle(ParseResult parseResult) throws ExecutionException { ... }
+     *
+     *     protected MyResultHandler self() { return this; }
+     * }
+     * }
+ * @deprecated see {@link #execute(String...)}, {@link #getExecutionStrategy()}, {@link #getParameterExceptionHandler()}, {@link #getExecutionExceptionHandler()} + * @since 3.0 */ + @Deprecated public abstract static class AbstractParseResultHandler extends AbstractHandler> implements IParseResultHandler2, IExecutionStrategy { + /** Prints help if requested, and otherwise calls {@link #handle(CommandLine.ParseResult)}. + * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}. + * + * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments + * @return the result of {@link #handle(CommandLine.ParseResult) processing parse results} + * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions} + * thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2} + * @throws ExecutionException if a problem occurred while processing the parse results; client code can use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + */ + public R handleParseResult(ParseResult parseResult) throws ExecutionException { + if (printHelpIfRequested(parseResult.asCommandLineList(), out(), err(), colorScheme())) { + return returnResultOrExit(null); + } + return returnResultOrExit(handle(parseResult)); + } + + public int execute(ParseResult parseResult) throws ExecutionException { + Integer helpExitCode = executeHelpRequest(parseResult); + if (helpExitCode != null) { return helpExitCode; } + + Tracer t = CommandLine.tracer(); + t.debug("%s: handling ParseResult...", getClass().getSimpleName()); + R executionResult = handle(parseResult); + List exitCodeGenerators = extractExitCodeGenerators(parseResult); + t.debug("%s: ParseResult has %s exit code generators", getClass().getSimpleName(), exitCodeGenerators.size()); + return resolveExitCode(parseResult.commandSpec().exitCodeOnSuccess(), executionResult, exitCodeGenerators); + } + + // Use the highest value (or if all values are negative, use the lowest value). + private int resolveExitCode(int exitCodeOnSuccess, R executionResult, List exitCodeGenerators) { + int result = 0; + for (IExitCodeGenerator generator : exitCodeGenerators) { + try { + int exitCode = generator.getExitCode(); + if ((exitCode > 0 && exitCode > result) || (exitCode < result && result <= 0)) { + result = exitCode; + } + } catch (Exception ex) { + result = (result == 0) ? 1 : result; + ex.printStackTrace(); + } + } + Tracer t = CommandLine.tracer(); + t.debug("resolveExitCode: exit code generators resulted in exit code=%d", result); + if (executionResult instanceof List) { + List resultList = (List) executionResult; + for (Object obj : resultList) { + if (obj instanceof Integer) { + int exitCode = (Integer) obj; + if ((exitCode > 0 && exitCode > result) || (exitCode < result && result <= 0)) { + result = exitCode; + } + } + } + } + t.debug("resolveExitCode: execution results resulted in exit code=%d", result); + t.debug("resolveExitCode: returning exit code=%d", result == 0 ? exitCodeOnSuccess : result); + return result == 0 ? exitCodeOnSuccess : result; + } + + /** Processes the specified {@code ParseResult} and returns the result as a list of objects. + * Implementations are responsible for catching any exceptions thrown in the {@code handle} method, and + * rethrowing an {@code ExecutionException} that details the problem and captures the offending {@code CommandLine} object. + * + * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments + * @return the result of processing parse results + * @throws ExecutionException if a problem occurred while processing the parse results; client code can use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + */ + protected abstract R handle(ParseResult parseResult) throws ExecutionException; + + protected List extractExitCodeGenerators(ParseResult parseResult) { return Collections.emptyList(); } + } + /** + * Command line {@linkplain IExecutionStrategy execution strategy} that prints help if requested, and otherwise executes the top-level + * {@code Runnable} or {@code Callable} command. + * For use by the {@link #execute(String...) execute} method. + * @since 2.0 */ + public static class RunFirst extends AbstractParseResultHandler> implements IParseResultHandler { + /** {@inheritDoc} */ + public int execute(ParseResult parseResult) throws ExecutionException { return super.execute(parseResult); } + + /** Prints help if requested, and otherwise executes the top-level {@code Runnable} or {@code Callable} command. + * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}. + * If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException} + * is thrown detailing the problem and capturing the offending {@code CommandLine} object. + * + * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments + * @param out the {@code PrintStream} to print help to if requested + * @param ansi for printing help messages using ANSI styles and colors + * @return an empty list if help was requested, or a list containing a single element: the result of calling the + * {@code Callable}, or a {@code null} element if the top-level command was a {@code Runnable} + * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions} + * thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + */ + public List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi) { + if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); } + return returnResultOrExit(executeUserObject(parsedCommands.get(0), new ArrayList())); + } + /** Executes the top-level {@code Runnable} or {@code Callable} subcommand. + * If the top-level command does not implement either {@code Runnable} or {@code Callable} and is not a {@code Method}, an {@code ExecutionException} + * is thrown detailing the problem and capturing the offending {@code CommandLine} object. + * + * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments + * @return an empty list if help was requested, or a list containing a single element: the result of calling the + * {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + * @since 3.0 */ + protected List handle(ParseResult parseResult) throws ExecutionException { + Tracer t = CommandLine.tracer(); + t.debug("RunFirst: executing user object for '%s'...", parseResult.commandSpec().qualifiedName()); + return executeUserObject(parseResult.commandSpec().commandLine(), new ArrayList()); // first + } + + protected List extractExitCodeGenerators(ParseResult parseResult) { + if (parseResult.commandSpec().userObject() instanceof IExitCodeGenerator) { + return Collections.singletonList((IExitCodeGenerator) parseResult.commandSpec().userObject()); + } + return Collections.emptyList(); + } + + @Override protected RunFirst self() { return this; } + } + /** + * Command line {@linkplain IExecutionStrategy execution strategy} that prints help if requested, and otherwise executes the most specific + * {@code Runnable} or {@code Callable} subcommand. + * For use by the {@link #execute(String...) execute} method. + *

+ * Something like this:

+ *
{@code
+     *     // RunLast implementation: print help if requested, otherwise execute the most specific subcommand
+     *     List parsedCommands = parseResult.asCommandLineList();
+     *     if (CommandLine.printHelpIfRequested(parsedCommands, out(), err(), ansi())) {
+     *         return emptyList();
+     *     }
+     *     CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
+     *     Object command = last.getCommand();
+     *     Object result = null;
+     *     if (command instanceof Runnable) {
+     *         try {
+     *             ((Runnable) command).run();
+     *         } catch (Exception ex) {
+     *             throw new ExecutionException(last, "Error in runnable " + command, ex);
+     *         }
+     *     } else if (command instanceof Callable) {
+     *         try {
+     *             result = ((Callable) command).call();
+     *         } catch (Exception ex) {
+     *             throw new ExecutionException(last, "Error in callable " + command, ex);
+     *         }
+     *     } else {
+     *         throw new ExecutionException(last, "Parsed command (" + command + ") is not Runnable or Callable");
+     *     }
+     *     last.setExecutionResult(result);
+     *     return Arrays.asList(result);
+     * }
+ *

+ * From acrostics v2.0, {@code RunLast} is used to implement the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run} + * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} convenience methods. + *

+ * @since 2.0 */ + public static class RunLast extends AbstractParseResultHandler> implements IParseResultHandler { + /** {@inheritDoc} */ + public int execute(ParseResult parseResult) throws ExecutionException { return super.execute(parseResult); } + + /** Prints help if requested, and otherwise executes the most specific {@code Runnable} or {@code Callable} subcommand. + *

For {@linkplain Command#subcommandsRepeatable() repeatable subcommands}, this method + * may execute multiple subcommands: the most deeply nested subcommands that have the same parent command.

+ *

Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.

+ *

If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException} + * is thrown detailing the problem and capturing the offending {@code CommandLine} object.

+ * + * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments + * @param out the {@code PrintStream} to print help to if requested + * @param ansi for printing help messages using ANSI styles and colors + * @return an empty list if help was requested, or a list containing a single element: the result of calling the + * {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable} + * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions} + * thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + */ + public List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi) { + if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); } + return returnResultOrExit(executeUserObjectOfLastSubcommandWithSameParent(parsedCommands)); + } + /** Executes the most specific {@code Runnable} or {@code Callable} subcommand. + *

For {@linkplain Command#subcommandsRepeatable() repeatable subcommands}, this method + * may execute multiple subcommands: the most deeply nested subcommands that have the same parent command.

+ *

If the user object of the executed (sub)command does not implement either {@code Runnable} or {@code Callable} and is not a {@code Method}, an {@code ExecutionException} + * is thrown detailing the problem and capturing the offending {@code CommandLine} object.

+ * + * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments + * @return an empty list if help was requested, or a list containing a single element: the result of calling the + * {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + * @since 3.0 */ + protected List handle(ParseResult parseResult) throws ExecutionException { + return executeUserObjectOfLastSubcommandWithSameParent(parseResult.asCommandLineList()); + } + private static List executeUserObjectOfLastSubcommandWithSameParent(List parsedCommands) { + Tracer t = CommandLine.tracer(); + int start = indexOfLastSubcommandWithSameParent(parsedCommands); + List result = new ArrayList(); + for (int i = start; i < parsedCommands.size(); i++) { + t.debug("RunLast: executing user object for '%s'...", parsedCommands.get(i).commandSpec.qualifiedName()); + executeUserObject(parsedCommands.get(i), result); + } + return result; + } + // find list of most deeply nested sub-(sub*)-commands + private static int indexOfLastSubcommandWithSameParent(List parsedCommands) { + int start = parsedCommands.size() - 1; + for (int i = parsedCommands.size() - 2; i >= 0; i--) { + if (parsedCommands.get(i).getParent() != parsedCommands.get(i + 1).getParent()) { break; } + start = i; + } + return start; + } + + protected List extractExitCodeGenerators(ParseResult parseResult) { + List parsedCommands = parseResult.asCommandLineList(); + int start = indexOfLastSubcommandWithSameParent(parsedCommands); + List result = new ArrayList(); + for (int i = start; i < parsedCommands.size(); i++) { + Object userObject = parsedCommands.get(i).getCommandSpec().userObject(); + if (userObject instanceof IExitCodeGenerator) { result.add((IExitCodeGenerator) userObject); } + } + return result; + } + @Override protected RunLast self() { return this; } + } + /** + * Command line {@linkplain IExecutionStrategy execution strategy} that prints help if requested, and otherwise executes the top-level command and + * all subcommands as {@code Runnable}, {@code Callable} or {@code Method}. + * For use by the {@link #execute(String...) execute} method. + * @since 2.0 */ + public static class RunAll extends AbstractParseResultHandler> implements IParseResultHandler { + /** {@inheritDoc} */ + public int execute(ParseResult parseResult) throws ExecutionException { return super.execute(parseResult); } + + /** Prints help if requested, and otherwise executes the top-level command and all subcommands as {@code Runnable}, + * {@code Callable} or {@code Method}. Finally, either a list of result objects is returned, or the JVM is terminated if an exit + * code {@linkplain #andExit(int) was set}. If any of the {@code CommandLine} commands does not implement either + * {@code Runnable} or {@code Callable}, an {@code ExecutionException} + * is thrown detailing the problem and capturing the offending {@code CommandLine} object. + * + * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments + * @param out the {@code PrintStream} to print help to if requested + * @param ansi for printing help messages using ANSI styles and colors + * @return an empty list if help was requested, or a list containing the result of executing all commands: + * the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable} + * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions} + * thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + */ + public List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi) { + if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); } + List result = new ArrayList(); + for (CommandLine parsed : parsedCommands) { + executeUserObject(parsed, result); + } + return returnResultOrExit(result); + } + /** Executes the top-level command and all subcommands as {@code Runnable} or {@code Callable}. + * If any of the {@code CommandLine} commands does not implement either {@code Runnable} or {@code Callable} and is not a {@code Method}, an {@code ExecutionException} + * is thrown detailing the problem and capturing the offending {@code CommandLine} object. + * + * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments + * @return an empty list if help was requested, or a list containing the result of executing all commands: + * the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable} + * @throws ExecutionException if a problem occurred while processing the parse results; use + * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + * @since 3.0 */ + protected List handle(ParseResult parseResult) throws ExecutionException { + Tracer t = CommandLine.tracer(); + return returnResultOrExit(recursivelyExecuteUserObject(parseResult, new ArrayList(), t)); + } + private List recursivelyExecuteUserObject(ParseResult parseResult, List result, Tracer t) throws ExecutionException { + t.debug("%s: executing user object for '%s'...", getClass().getSimpleName(), parseResult.commandSpec.qualifiedName()); + executeUserObject(parseResult.commandSpec().commandLine(), result); + for (ParseResult pr : parseResult.subcommands()) { + recursivelyExecuteUserObject(pr, result, t); + } + return result; + } + protected List extractExitCodeGenerators(ParseResult parseResult) { + return recursivelyExtractExitCodeGenerators(parseResult, new ArrayList()); + } + private List recursivelyExtractExitCodeGenerators(ParseResult parseResult, List result) throws ExecutionException { + if (parseResult.commandSpec().userObject() instanceof IExitCodeGenerator) { result.add((IExitCodeGenerator) parseResult.commandSpec().userObject()); } + for (ParseResult pr : parseResult.subcommands()) { + recursivelyExtractExitCodeGenerators(pr, result); + } + return result; + } + @Override protected RunAll self() { return this; } + } + + /** + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 2.0 */ + @Deprecated public List parseWithHandler(IParseResultHandler handler, PrintStream out, String... args) { + return parseWithHandlers(handler, out, Help.Ansi.AUTO, defaultExceptionHandler(), args); + } + /** + * Returns the result of calling {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)} with + * a new {@link DefaultExceptionHandler} in addition to the specified parse result handler and the specified command line arguments. + *

+ * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run} + * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better + * support for nested subcommands. + *

+ *

Calling this method roughly expands to:

+ *
{@code
+     * try {
+     *     ParseResult parseResult = parseArgs(args);
+     *     return handler.handleParseResult(parseResult);
+     * } catch (ParameterException ex) {
+     *     return new DefaultExceptionHandler().handleParseException(ex, args);
+     * }
+     * }
+ *

+ * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code. + * The following handlers are available:

+ *
    + *
  • {@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand + * and tries to execute it as a {@code Runnable} or {@code Callable}.
  • + *
  • {@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.
  • + *
  • {@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.
  • + *
  • {@link DefaultExceptionHandler} prints the error message followed by usage help
  • + *
+ * @param the return type of this handler + * @param handler the function that will handle the result of successfully parsing the command line arguments + * @param args the command line arguments + * @return an object resulting from handling the parse result or the exception that occurred while parsing the input + * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the + * parse results; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + * @see RunLast + * @see RunAll + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.0 */ + @Deprecated public R parseWithHandler(IParseResultHandler2 handler, String[] args) { + return parseWithHandlers(handler, new DefaultExceptionHandler(), args); + } + + /** + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 2.0 */ + @Deprecated public List parseWithHandlers(IParseResultHandler handler, PrintStream out, Help.Ansi ansi, IExceptionHandler exceptionHandler, String... args) { + clearExecutionResults(); + try { + List result = parse(args); + return handler.handleParseResult(result, out, ansi); + } catch (ParameterException ex) { + return exceptionHandler.handleException(ex, out, ansi, args); + } + } + /** + * Tries to {@linkplain #parseArgs(String...) parse} the specified command line arguments, and if successful, delegates + * the processing of the resulting {@code ParseResult} object to the specified {@linkplain IParseResultHandler2 handler}. + * If the command line arguments were invalid, the {@code ParameterException} thrown from the {@code parse} method + * is caught and passed to the specified {@link IExceptionHandler2}. + *

+ * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run} + * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better + * support for nested subcommands. + *

+ *

Calling this method roughly expands to:

+ *
+     * ParseResult parseResult = null;
+     * try {
+     *     parseResult = parseArgs(args);
+     *     return handler.handleParseResult(parseResult);
+     * } catch (ParameterException ex) {
+     *     return exceptionHandler.handleParseException(ex, (String[]) args);
+     * } catch (ExecutionException ex) {
+     *     return exceptionHandler.handleExecutionException(ex, parseResult);
+     * }
+     * 
+ *

+ * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code. + * The following handlers are available:

+ *
    + *
  • {@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand + * and tries to execute it as a {@code Runnable} or {@code Callable}.
  • + *
  • {@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.
  • + *
  • {@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.
  • + *
  • {@link DefaultExceptionHandler} prints the error message followed by usage help
  • + *
+ * + * @param handler the function that will handle the result of successfully parsing the command line arguments + * @param exceptionHandler the function that can handle the {@code ParameterException} thrown when the command line arguments are invalid + * @param args the command line arguments + * @return an object resulting from handling the parse result or the exception that occurred while parsing the input + * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the parse + * result {@code ParseResult} object; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed + * @param the return type of the result handler and exception handler + * @see RunLast + * @see RunAll + * @see DefaultExceptionHandler + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.0 */ + @Deprecated public R parseWithHandlers(IParseResultHandler2 handler, IExceptionHandler2 exceptionHandler, String... args) { + clearExecutionResults(); + ParseResult parseResult = null; + try { + parseResult = parseArgs(args); + return handler.handleParseResult(parseResult); + } catch (ParameterException ex) { + return exceptionHandler.handleParseException(ex, args); + } catch (ExecutionException ex) { + return exceptionHandler.handleExecutionException(ex, parseResult); + } + } + static String versionString() { + return String.format("%s, JVM: %s (%s %s %s), OS: %s %s %s", VERSION, + System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("java.vm.name"), System.getProperty("java.vm.version"), + System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")); + } + /** + * Equivalent to {@code new CommandLine(command).usage(out)}. See {@link #usage(PrintStream)} for details. + * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters} + * @param out the print stream to print the help message to + * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + */ + public static void usage(Object command, PrintStream out) { + toCommandLine(command, new DefaultFactory()).usage(out); + } + + /** + * Equivalent to {@code new CommandLine(command).usage(out, ansi)}. + * See {@link #usage(PrintStream, Help.Ansi)} for details. + * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters} + * @param out the print stream to print the help message to + * @param ansi whether the usage message should contain ANSI escape codes or not + * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + */ + public static void usage(Object command, PrintStream out, Help.Ansi ansi) { + toCommandLine(command, new DefaultFactory()).usage(out, ansi); + } + + /** + * Equivalent to {@code new CommandLine(command).usage(out, colorScheme)}. + * See {@link #usage(PrintStream, Help.ColorScheme)} for details. + * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters} + * @param out the print stream to print the help message to + * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled + * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + */ + public static void usage(Object command, PrintStream out, Help.ColorScheme colorScheme) { + toCommandLine(command, new DefaultFactory()).usage(out, colorScheme); + } + + /** + * Delegates to {@link #usage(PrintStream, Help.ColorScheme)} with the {@linkplain #getColorScheme() configured} color scheme. + * @param out the printStream to print to + * @see #usage(PrintStream, Help.ColorScheme) + */ + public void usage(PrintStream out) { usage(out, getColorScheme()); } + /** + * Delegates to {@link #usage(PrintWriter, Help.ColorScheme)} with the {@linkplain #getColorScheme() configured} color scheme. + * @param writer the PrintWriter to print to + * @see #usage(PrintWriter, Help.ColorScheme) + * @since 3.0 */ + public void usage(PrintWriter writer) { usage(writer, getColorScheme()); } + + /** + * Delegates to {@link #usage(PrintStream, Help.ColorScheme)} with the {@linkplain Help#defaultColorScheme(CommandLine.Help.Ansi) default color scheme}. + * @param out the printStream to print to + * @param ansi whether the usage message should include ANSI escape codes or not + * @see #usage(PrintStream, Help.ColorScheme) + */ + public void usage(PrintStream out, Help.Ansi ansi) { usage(out, Help.defaultColorScheme(ansi)); } + /** Similar to {@link #usage(PrintStream, Help.Ansi)} but with the specified {@code PrintWriter} instead of a {@code PrintStream}. + * @since 3.0 */ + public void usage(PrintWriter writer, Help.Ansi ansi) { usage(writer, Help.defaultColorScheme(ansi)); } + + /** + * Prints a usage help message for the annotated command class to the specified {@code PrintStream}. + * Delegates construction of the usage help message to the {@link Help} inner class and is equivalent to: + *
+     * Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO);
+     * Help help = getHelpFactory().create(getCommandSpec(), colorScheme)
+     * StringBuilder sb = new StringBuilder();
+     * for (String key : getHelpSectionKeys()) {
+     *     IHelpSectionRenderer renderer = getHelpSectionMap().get(key);
+     *     if (renderer != null) { sb.append(renderer.render(help)); }
+     * }
+     * out.print(sb);
+     * 
+ *

Annotate your class with {@link Command} to control many aspects of the usage help message, including + * the program name, text of section headings and section contents, and some aspects of the auto-generated sections + * of the usage help message. + *

To customize the auto-generated sections of the usage help message, like how option details are displayed, + * instantiate a {@link Help} object and use a {@link Help.TextTable} with more of fewer columns, a custom + * {@linkplain Help.Layout layout}, and/or a custom option {@linkplain Help.IOptionRenderer renderer} + * for ultimate control over which aspects of an Option or Field are displayed where.

+ * @param out the {@code PrintStream} to print the usage help message to + * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled + * @see UsageMessageSpec + */ + public void usage(PrintStream out, Help.ColorScheme colorScheme) { + out.print(usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme))); + out.flush(); + } + /** Similar to {@link #usage(PrintStream, Help.ColorScheme)}, but with the specified {@code PrintWriter} instead of a {@code PrintStream}. + * @since 3.0 */ + public void usage(PrintWriter writer, Help.ColorScheme colorScheme) { + writer.print(usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme))); + writer.flush(); + } + /** Similar to {@link #usage(PrintStream)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}. + * @since 3.2 */ + public String getUsageMessage() { + return usage(new StringBuilder(), getHelp()).toString(); + } + /** Similar to {@link #usage(PrintStream, Help.Ansi)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}. + * @since 3.2 */ + public String getUsageMessage(Help.Ansi ansi) { + return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), Help.defaultColorScheme(ansi))).toString(); + } + /** Similar to {@link #usage(PrintStream, Help.ColorScheme)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}. + * @since 3.2 */ + public String getUsageMessage(Help.ColorScheme colorScheme) { + return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme)).toString(); + } + + private StringBuilder usage(StringBuilder sb, Help help) { + for (String key : getHelpSectionKeys()) { + IHelpSectionRenderer renderer = getHelpSectionMap().get(key); + if (renderer != null) { sb.append(renderer.render(help)); } + } + return sb; + } + + /** + * Delegates to {@link #printVersionHelp(PrintStream, Help.Ansi)} with the ANSI setting of the {@linkplain #getColorScheme() configured} color scheme. + * @param out the printStream to print to + * @see #printVersionHelp(PrintStream, Help.Ansi) + * @since 0.9.8 + */ + public void printVersionHelp(PrintStream out) { printVersionHelp(out, getColorScheme().ansi()); } + + /** + * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}. + * Each element of the array of version strings is printed on a separate line. Version strings may contain + * markup for colors and style. + * @param out the printStream to print to + * @param ansi whether the usage message should include ANSI escape codes or not + * @see Command#version() + * @see Option#versionHelp() + * @see #isVersionHelpRequested() + * @since 0.9.8 + */ + public void printVersionHelp(PrintStream out, Help.Ansi ansi) { + for (String versionInfo : getCommandSpec().version()) { + out.println(ansi.new Text(versionInfo, getColorScheme())); + } + out.flush(); + } + /** + * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}. + * Each element of the array of version strings is {@linkplain String#format(String, Object...) formatted} with the + * specified parameters, and printed on a separate line. Both version strings and parameters may contain + * markup for colors and style. + * @param out the printStream to print to + * @param ansi whether the usage message should include ANSI escape codes or not + * @param params Arguments referenced by the format specifiers in the version strings + * @see Command#version() + * @see Option#versionHelp() + * @see #isVersionHelpRequested() + * @since 1.0.0 + */ + public void printVersionHelp(PrintStream out, Help.Ansi ansi, Object... params) { + for (String versionInfo : getCommandSpec().version()) { + out.println(ansi.new Text(format(versionInfo, params), getColorScheme())); + } + out.flush(); + } + /** + * Delegates to {@link #printVersionHelp(PrintWriter, Help.Ansi, Object...)} with the ANSI setting of the {@linkplain #getColorScheme() configured} color scheme. + * @param out the PrintWriter to print to + * @since 4.0 */ + public void printVersionHelp(PrintWriter out) { printVersionHelp(out, getColorScheme().ansi()); } + /** + * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintWriter}. + * Each element of the array of version strings is {@linkplain String#format(String, Object...) formatted} with the + * specified parameters, and printed on a separate line. Both version strings and parameters may contain + * markup for colors and style. + * @param out the PrintWriter to print to + * @param ansi whether the usage message should include ANSI escape codes or not + * @param params Arguments referenced by the format specifiers in the version strings + * @see Command#version() + * @see Option#versionHelp() + * @see #isVersionHelpRequested() + * @since 4.0 */ + public void printVersionHelp(PrintWriter out, Help.Ansi ansi, Object... params) { + for (String versionInfo : getCommandSpec().version()) { + out.println(ansi.new Text(format(versionInfo, params), getColorScheme())); + } + out.flush(); + } + + /** + * Equivalent to {@code new CommandLine(callable).execute(args)}, except for the return value. + * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param args the command line arguments to parse + * @param the annotated object must implement Callable + * @param the return type of the most specific command (must implement {@code Callable}) + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @see #execute(String...) + * @since 3.0 + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + */ + @Deprecated public static , T> T call(C callable, String... args) { + CommandLine cmd = new CommandLine(callable); + List results = cmd.parseWithHandler(new RunLast(), args); + return CommandLine.firstElement(results); + } + + /** + * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for + * diagnostic error messages and {@link Help.Ansi#AUTO}. + * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param out the printStream to print the usage help message to when the user requested help + * @param args the command line arguments to parse + * @param the annotated object must implement Callable + * @param the return type of the most specific command (must implement {@code Callable}) + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @see RunLast + */ + @Deprecated public static , T> T call(C callable, PrintStream out, String... args) { + return call(callable, out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages. + * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param out the printStream to print the usage help message to when the user requested help + * @param ansi the ANSI style to use + * @param args the command line arguments to parse + * @param the annotated object must implement Callable + * @param the return type of the most specific command (must implement {@code Callable}) + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @see RunLast + */ + @Deprecated public static , T> T call(C callable, PrintStream out, Help.Ansi ansi, String... args) { + return call(callable, out, System.err, ansi, args); + } + /** + * Convenience method to allow command line application authors to avoid some boilerplate code in their application. + * The annotated object needs to implement {@link Callable}. + *

Consider using the {@link #execute(String...)} method instead:

+ *
{@code
+     * CommandLine cmd = new CommandLine(callable)
+     *         .setOut(myOutWriter()) // System.out by default
+     *         .setErr(myErrWriter()) // System.err by default
+     *         .setColorScheme(myColorScheme()); // default color scheme, Ansi.AUTO by default
+     * int exitCode = cmd.execute(args);
+     * //System.exit(exitCode);
+     * }
+ *

+ * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the + * command line is executed. + *

+ * @param callable the command to call when {@linkplain #parse(String...) parsing} succeeds. + * @param out the printStream to print the usage help message to when the user requested help + * @param err the printStream to print diagnostic messages to + * @param ansi including whether the usage message should include ANSI escape codes or not + * @param args the command line arguments to parse + * @param the annotated object must implement Callable + * @param the return type of the specified {@code Callable} + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.0 + */ + @Deprecated public static , T> T call(C callable, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) { + CommandLine cmd = new CommandLine(callable); + List results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler>().useErr(err).useAnsi(ansi), args); + return CommandLine.firstElement(results); + } + /** + * Equivalent to {@code new CommandLine(callableClass, factory).execute(args)}, except for the return value. + * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified callable class and potentially inject other components + * @param args the command line arguments to parse + * @param the annotated class must implement Callable + * @param the return type of the most specific command (must implement {@code Callable}) + * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @see #execute(String...) + * @since 3.2 + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + */ + @Deprecated public static , T> T call(Class callableClass, IFactory factory, String... args) { + CommandLine cmd = new CommandLine(callableClass, factory); + List results = cmd.parseWithHandler(new RunLast(), args); + return CommandLine.firstElement(results); + } + /** + * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with + * {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}. + * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components + * @param out the printStream to print the usage help message to when the user requested help + * @param args the command line arguments to parse + * @param the annotated class must implement Callable + * @param the return type of the most specific command (must implement {@code Callable}) + * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.2 + */ + @Deprecated public static , T> T call(Class callableClass, IFactory factory, PrintStream out, String... args) { + return call(callableClass, factory, out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with + * {@code System.err} for diagnostic error messages. + * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components + * @param out the printStream to print the usage help message to when the user requested help + * @param ansi the ANSI style to use + * @param args the command line arguments to parse + * @param the annotated class must implement Callable + * @param the return type of the most specific command (must implement {@code Callable}) + * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.2 + */ + @Deprecated public static , T> T call(Class callableClass, IFactory factory, PrintStream out, Help.Ansi ansi, String... args) { + return call(callableClass, factory, out, System.err, ansi, args); + } + + /** + * Convenience method to allow command line application authors to avoid some boilerplate code in their application. + * The specified {@linkplain IFactory factory} will create an instance of the specified {@code callableClass}; + * use this method instead of {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call(Callable, ...)} + * if you want to use a factory that performs Dependency Injection. + * The annotated class needs to implement {@link Callable}. + *

Consider using the {@link #execute(String...)} method instead:

+ *
{@code
+     * CommandLine cmd = new CommandLine(callableClass, factory)
+     *         .setOut(myOutWriter()) // System.out by default
+     *         .setErr(myErrWriter()) // System.err by default
+     *         .setColorScheme(myColorScheme()); // default color scheme, Ansi.AUTO by default
+     * int exitCode = cmd.execute(args);
+     * //System.exit(exitCode);
+     * }
+ *

+ * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the + * command line is executed. + *

+ * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components + * @param out the printStream to print the usage help message to when the user requested help + * @param err the printStream to print diagnostic messages to + * @param ansi the ANSI style to use + * @param args the command line arguments to parse + * @param the annotated class must implement Callable + * @param the return type of the most specific command (must implement {@code Callable}) + * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Callable throws an exception + * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.2 + */ + @Deprecated public static , T> T call(Class callableClass, IFactory factory, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) { + CommandLine cmd = new CommandLine(callableClass, factory); + List results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler>().useErr(err).useAnsi(ansi), args); + return CommandLine.firstElement(results); + } + + @SuppressWarnings("unchecked") private static T firstElement(List results) { + return (results == null || results.isEmpty()) ? null : (T) results.get(0); + } + + /** + * Equivalent to {@code new CommandLine(runnable).execute(args)}. + * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param args the command line arguments to parse + * @param the annotated object must implement Runnable + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Runnable throws an exception + * @see #execute(String...) + * @since 3.0 + * @deprecated use {@link #execute(String...)} instead + */ + @Deprecated public static void run(R runnable, String... args) { + run(runnable, System.out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages and {@link Help.Ansi#AUTO}. + * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param out the printStream to print the usage help message to when the user requested help + * @param args the command line arguments to parse + * @param the annotated object must implement Runnable + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Runnable throws an exception + * @deprecated use {@link #execute(String...)} instead + * @see RunLast + */ + @Deprecated public static void run(R runnable, PrintStream out, String... args) { + run(runnable, out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages. + * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param out the printStream to print the usage help message to when the user requested help + * @param ansi whether the usage message should include ANSI escape codes or not + * @param args the command line arguments to parse + * @param the annotated object must implement Runnable + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Runnable throws an exception + * @deprecated use {@link #execute(String...)} instead + * @see RunLast + */ + @Deprecated public static void run(R runnable, PrintStream out, Help.Ansi ansi, String... args) { + run(runnable, out, System.err, ansi, args); + } + /** + * Convenience method to allow command line application authors to avoid some boilerplate code in their application. + * The annotated object needs to implement {@link Runnable}. + *

Consider using the {@link #execute(String...)} method instead:

+ *
{@code
+     * CommandLine cmd = new CommandLine(runnable)
+     *         .setOut(myOutWriter()) // System.out by default
+     *         .setErr(myErrWriter()) // System.err by default
+     *         .setColorScheme(myColorScheme()); // default color scheme, Ansi.AUTO by default
+     * int exitCode = cmd.execute(args);
+     * //System.exit(exitCode);
+     * }
+ *

+ * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the + * command line is executed. + *

+ * From acrostics v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) requested}, + * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}. + *

+ * @param runnable the command to run when {@linkplain #parse(String...) parsing} succeeds. + * @param out the printStream to print the usage help message to when the user requested help + * @param err the printStream to print diagnostic messages to + * @param ansi whether the usage message should include ANSI escape codes or not + * @param args the command line arguments to parse + * @param the annotated object must implement Runnable + * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Runnable throws an exception + * @deprecated use {@link #execute(String...)} instead + * @since 3.0 + */ + @Deprecated public static void run(R runnable, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) { + CommandLine cmd = new CommandLine(runnable); + cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler>().useErr(err).useAnsi(ansi), args); + } + /** + * Equivalent to {@code new CommandLine(runnableClass, factory).execute(args)}. + * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components + * @param args the command line arguments to parse + * @param the annotated class must implement Runnable + * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Runnable throws an exception + * @see #execute(String...) + * @since 3.2 + * @deprecated use {@link #execute(String...)} instead + */ + @Deprecated public static void run(Class runnableClass, IFactory factory, String... args) { + run(runnableClass, factory, System.out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with + * {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}. + * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components + * @param out the printStream to print the usage help message to when the user requested help + * @param args the command line arguments to parse + * @param the annotated class must implement Runnable + * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...) + * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Runnable throws an exception + * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) + * @see RunLast + * @deprecated use {@link #execute(String...)} instead + * @since 3.2 + */ + @Deprecated public static void run(Class runnableClass, IFactory factory, PrintStream out, String... args) { + run(runnableClass, factory, out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with + * {@code System.err} for diagnostic error messages. + * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components + * @param out the printStream to print the usage help message to when the user requested help + * @param ansi whether the usage message should include ANSI escape codes or not + * @param args the command line arguments to parse + * @param the annotated class must implement Runnable + * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...) + * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation + * @throws ExecutionException if the Runnable throws an exception + * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) + * @see RunLast + * @deprecated use {@link #execute(String...)} instead + * @since 3.2 + */ + @Deprecated public static void run(Class runnableClass, IFactory factory, PrintStream out, Help.Ansi ansi, String... args) { + run(runnableClass, factory, out, System.err, ansi, args); + } + + /** + * Convenience method to allow command line application authors to avoid some boilerplate code in their application. + * The specified {@linkplain IFactory factory} will create an instance of the specified {@code runnableClass}; + * use this method instead of {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run(Runnable, ...)} + * if you want to use a factory that performs Dependency Injection. + * The annotated class needs to implement {@link Runnable}. + *

Consider using the {@link #execute(String...)} method instead:

+ *
{@code
+     * CommandLine cmd = new CommandLine(runnableClass, factory)
+     *         .setOut(myOutWriter()) // System.out by default
+     *         .setErr(myErrWriter()) // System.err by default
+     *         .setColorScheme(myColorScheme()); // default color scheme, Ansi.AUTO by default
+     * int exitCode = cmd.execute(args);
+     * //System.exit(exitCode);
+     * }
+ *

+ * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the + * command line is executed. + *

+ * This method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) requested}, + * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}. + *

+ * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components + * @param out the printStream to print the usage help message to when the user requested help + * @param err the printStream to print diagnostic messages to + * @param ansi whether the usage message should include ANSI escape codes or not + * @param args the command line arguments to parse + * @param the annotated class must implement Runnable + * @deprecated use {@link #execute(String...)} instead + * @since 3.2 + */ + @Deprecated public static void run(Class runnableClass, IFactory factory, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) { + CommandLine cmd = new CommandLine(runnableClass, factory); + cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler>().useErr(err).useAnsi(ansi), args); + } + + /** + * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for + * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}. + * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from, + * and run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass + * @param args the command line arguments to parse + * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...) + * @throws InitializationException if the specified method does not have a {@link Command} annotation, + * or if the specified class contains multiple {@code @Command}-annotated methods with the specified name + * @throws ExecutionException if the Runnable throws an exception + * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) + * @since 3.6 + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + */ + @Deprecated public static Object invoke(String methodName, Class cls, String... args) { + return invoke(methodName, cls, System.out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with the specified stream for + * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}. + * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from, + * and run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass + * @param out the printstream to print requested help message to + * @param args the command line arguments to parse + * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...) + * @throws InitializationException if the specified method does not have a {@link Command} annotation, + * or if the specified class contains multiple {@code @Command}-annotated methods with the specified name + * @throws ExecutionException if the Runnable throws an exception + * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.6 + */ + @Deprecated public static Object invoke(String methodName, Class cls, PrintStream out, String... args) { + return invoke(methodName, cls, out, System.err, Help.Ansi.AUTO, args); + } + /** + * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with the specified stream for + * requested usage help messages, {@code System.err} for diagnostic error messages, and the specified Ansi mode. + * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from, + * and run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass + * @param out the printstream to print requested help message to + * @param ansi whether the usage message should include ANSI escape codes or not + * @param args the command line arguments to parse + * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...) + * @throws InitializationException if the specified method does not have a {@link Command} annotation, + * or if the specified class contains multiple {@code @Command}-annotated methods with the specified name + * @throws ExecutionException if the Runnable throws an exception + * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.6 + */ + @Deprecated public static Object invoke(String methodName, Class cls, PrintStream out, Help.Ansi ansi, String... args) { + return invoke(methodName, cls, out, System.err, ansi, args); + } + + /** + * Convenience method to allow command line application authors to avoid some boilerplate code in their application. + * Constructs a {@link CommandSpec} model from the {@code @Option} and {@code @Parameters}-annotated method parameters + * of the {@code @Command}-annotated method, parses the specified command line arguments and invokes the specified method. + *

Consider using the {@link #execute(String...)} method instead:

+ *
{@code
+     * Method commandMethod = getCommandMethods(cls, methodName).get(0);
+     * CommandLine cmd = new CommandLine(commandMethod)
+     *         .setOut(myOutWriter()) // System.out by default
+     *         .setErr(myErrWriter()) // System.err by default
+     *         .setColorScheme(myColorScheme()); // default color scheme, Ansi.AUTO by default
+     * int exitCode = cmd.execute(args);
+     * //System.exit(exitCode);
+     * }
+ * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from, + * and run when {@linkplain #parseArgs(String...) parsing} succeeds. + * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass + * @param out the printStream to print the usage help message to when the user requested help + * @param err the printStream to print diagnostic messages to + * @param ansi whether the usage message should include ANSI escape codes or not + * @param args the command line arguments to parse + * @throws InitializationException if the specified method does not have a {@link Command} annotation, + * or if the specified class contains multiple {@code @Command}-annotated methods with the specified name + * @throws ExecutionException if the method throws an exception + * @deprecated use {@link #execute(String...)} and {@link #getExecutionResult()} instead + * @since 3.6 + */ + @Deprecated public static Object invoke(String methodName, Class cls, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) { + List candidates = getCommandMethods(cls, methodName); + if (candidates.size() != 1) { throw new InitializationException("Expected exactly one @Command-annotated method for " + cls.getName() + "::" + methodName + "(...), but got: " + candidates); } + Method method = candidates.get(0); + CommandLine cmd = new CommandLine(method); + List list = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler>().useErr(err).useAnsi(ansi), args); + return list == null ? null : list.get(0); + } + /** + * Helper to get methods of a class annotated with {@link Command @Command} via reflection, optionally filtered by method name (not {@link Command#name() @Command.name}). + * Methods have to be either public (inherited) members or be declared by {@code cls}, that is "inherited" static or protected methods will not be picked up. + * + * @param cls the class to search for methods annotated with {@code @Command} + * @param methodName if not {@code null}, return only methods whose method name (not {@link Command#name() @Command.name}) equals this string. Ignored if {@code null}. + * @return the matching command methods, or an empty list + * @see #invoke(String, Class, String...) + * @since 3.6.0 + */ + public static List getCommandMethods(Class cls, String methodName) { + return getCommandMethods(cls, methodName, true); + } + private static List getCommandMethods(Class cls, String methodName, boolean includeInherited) { + Set candidates = new HashSet(); + if (includeInherited) { + // traverse public member methods (excludes static/non-public, includes inherited) + candidates.addAll(Arrays.asList(Assert.notNull(cls, "class").getMethods())); + } + // traverse directly declared methods (includes static/non-public, excludes inherited) + candidates.addAll(Arrays.asList(Assert.notNull(cls, "class").getDeclaredMethods())); + + List result = new ArrayList(); + for (Method method : candidates) { + if (method.isAnnotationPresent(Command.class)) { + if (methodName == null || methodName.equals(method.getName())) { result.add(method); } + } + } + Collections.sort(result, new Comparator() { + public int compare(Method o1, Method o2) { return o1.getName().compareTo(o2.getName()); } + }); + return result; + } + + /** + * Registers the specified type converter for the specified class. When initializing fields annotated with + * {@link Option}, the field's type is used as a lookup key to find the associated type converter, and this + * type converter converts the original command line argument string value to the correct type. + *

+ * Java 8 lambdas make it easy to register custom type converters: + *

+ *
+     * commandLine.registerConverter(java.nio.file.Path.class, s -> java.nio.file.Paths.get(s));
+     * commandLine.registerConverter(java.time.Duration.class, s -> java.time.Duration.parse(s));
+ *

+ * Built-in type converters are pre-registered for the following java 1.5 types: + *

+ *
    + *
  • all primitive types
  • + *
  • all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short
  • + *
  • any enum
  • + *
  • java.io.File
  • + *
  • java.math.BigDecimal
  • + *
  • java.math.BigInteger
  • + *
  • java.net.InetAddress
  • + *
  • java.net.URI
  • + *
  • java.net.URL
  • + *
  • java.nio.charset.Charset
  • + *
  • java.sql.Time
  • + *
  • java.util.Date
  • + *
  • java.util.UUID
  • + *
  • java.util.regex.Pattern
  • + *
  • StringBuilder
  • + *
  • CharSequence
  • + *
  • String
  • + *
+ *

The specified converter will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment the converter is registered. Subcommands added + * later will not have this converter added automatically. To ensure a custom type converter is available to all + * subcommands, register the type converter last, after adding subcommands.

+ * + * @param cls the target class to convert parameter string values to + * @param converter the class capable of converting string values to the specified target type + * @param the target type + * @return this CommandLine object, to allow method chaining + * @see #addSubcommand(String, Object) + */ + public CommandLine registerConverter(Class cls, ITypeConverter converter) { + interpreter.converterRegistry.put(Assert.notNull(cls, "class"), Assert.notNull(converter, "converter")); + for (CommandLine command : getCommandSpec().commands.values()) { + command.registerConverter(cls, converter); + } + return this; + } + + /** Returns the String that separates option names from option values when parsing command line options. + * @return the String the parser uses to separate option names from option values + * @see ParserSpec#separator() */ + public String getSeparator() { return getCommandSpec().parser().separator(); } + + /** Sets the String the parser uses to separate option names from option values to the specified value. + * The separator may also be set declaratively with the {@link CommandLine.Command#separator()} annotation attribute. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param separator the String that separates option names from option values + * @see ParserSpec#separator(String) + * @return this {@code CommandLine} object, to allow method chaining */ + public CommandLine setSeparator(String separator) { + getCommandSpec().parser().separator(Assert.notNull(separator, "separator")); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setSeparator(separator); + } + return this; + } + + /** Returns the ResourceBundle of this command or {@code null} if no resource bundle is set. + * @see Command#resourceBundle() + * @see CommandSpec#resourceBundle() + * @since 3.6 */ + public ResourceBundle getResourceBundle() { return getCommandSpec().resourceBundle(); } + + /** Sets the ResourceBundle containing usage help message strings. + *

The specified bundle will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will not be impacted. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param bundle the ResourceBundle containing usage help message strings + * @return this {@code CommandLine} object, to allow method chaining + * @see Command#resourceBundle() + * @see CommandSpec#resourceBundle(ResourceBundle) + * @since 3.6 */ + public CommandLine setResourceBundle(ResourceBundle bundle) { + getCommandSpec().resourceBundle(bundle); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setResourceBundle(bundle); + } + return this; + } + + /** Returns the maximum width of the usage help message. The default is 80. + * @see UsageMessageSpec#width() */ + public int getUsageHelpWidth() { return getCommandSpec().usageMessage().width(); } + + /** Sets the maximum width of the usage help message. Longer lines are wrapped. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param width the maximum width of the usage help message + * @see UsageMessageSpec#width(int) + * @return this {@code CommandLine} object, to allow method chaining */ + public CommandLine setUsageHelpWidth(int width) { + getCommandSpec().usageMessage().width(width); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setUsageHelpWidth(width); + } + return this; + } + + /** Returns the maximum usage help long options column max width to the specified value. + * This value controls the maximum width of the long options column: any positional parameter + * labels or long options that are longer than the specified value will overflow into + * the description column, and cause the description to be displayed on the next line. + * @see UsageMessageSpec#longOptionsMaxWidth() + * @since 4.2*/ + public int getUsageHelpLongOptionsMaxWidth() { return getCommandSpec().usageMessage().longOptionsMaxWidth(); } + + /** Returns the maximum usage help long options column max width to the specified value. + * This value controls the maximum width of the long options column: any positional parameter + * labels or long options that are longer than the specified value will overflow into + * the description column, and cause the description to be displayed on the next line. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param columnWidth the new maximum usage help long options column max width. Must be 20 or greater. + * @see UsageMessageSpec#longOptionsMaxWidth(int) + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.2 */ + public CommandLine setUsageHelpLongOptionsMaxWidth(int columnWidth) { + getCommandSpec().usageMessage().longOptionsMaxWidth(columnWidth); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setUsageHelpLongOptionsMaxWidth(columnWidth); + } + return this; + } + + /** Returns whether acrostics should attempt to detect the terminal size and adjust the usage help message width + * to take the full terminal width. End users may enable this by setting system property {@code "acrostics.usage.width"} to {@code AUTO}, + * and may disable this by setting this system property to a {@linkplain UsageMessageSpec#width() numeric value}. + * This feature requires Java 7 or greater. The default is {@code false}. + * @see UsageMessageSpec#autoWidth() + * @since 4.0 */ + public boolean isUsageHelpAutoWidth() { return getCommandSpec().usageMessage().autoWidth(); } + + /** Sets whether acrostics should attempt to detect the terminal size and adjust the usage help message width + * to take the full terminal width. The default is {@code false}. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * @param detectTerminalSize whether acrostics should attempt to detect the terminal size + * @see UsageMessageSpec#autoWidth(boolean) + * @return this {@code CommandLine} object, to allow method chaining + * @since 4.0 */ + public CommandLine setUsageHelpAutoWidth(boolean detectTerminalSize) { + getCommandSpec().usageMessage().autoWidth(detectTerminalSize); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setUsageHelpAutoWidth(detectTerminalSize); + } + return this; + } + + /** Returns the command name (also called program name) displayed in the usage help synopsis. + * @return the command name (also called program name) displayed in the usage + * @see CommandSpec#name() + * @since 2.0 */ + public String getCommandName() { return getCommandSpec().name(); } + + /** Sets the command name (also called program name) displayed in the usage help synopsis to the specified value. + * Note that this method only modifies the usage help message, it does not impact parsing behaviour. + * The command name may also be set declaratively with the {@link CommandLine.Command#name()} annotation attribute. + * @param commandName command name (also called program name) displayed in the usage help synopsis + * @return this {@code CommandLine} object, to allow method chaining + * @see CommandSpec#name(String) + * @since 2.0 */ + public CommandLine setCommandName(String commandName) { + getCommandSpec().name(Assert.notNull(commandName, "commandName")); + return this; + } + + /** Returns whether arguments starting with {@code '@'} should be treated as the path to an argument file and its + * contents should be expanded into separate arguments for each line in the specified file. + * This property is {@code true} by default. + * @return whether "argument files" or {@code @files} should be expanded into their content + * @see ParserSpec#expandAtFiles() + * @since 2.1 */ + public boolean isExpandAtFiles() { return getCommandSpec().parser().expandAtFiles(); } + + /** Sets whether arguments starting with {@code '@'} should be treated as the path to an argument file and its + * contents should be expanded into separate arguments for each line in the specified file. ({@code true} by default.) + * @param expandAtFiles whether "argument files" or {@code @files} should be expanded into their content + * @return this {@code CommandLine} object, to allow method chaining + * @see ParserSpec#expandAtFiles(boolean) + * @since 2.1 */ + public CommandLine setExpandAtFiles(boolean expandAtFiles) { + getCommandSpec().parser().expandAtFiles(expandAtFiles); + return this; + } + + /** Returns the character that starts a single-line comment or {@code null} if all content of argument files should + * be interpreted as arguments (without comments). + * If specified, all characters from the comment character to the end of the line are ignored. + * @return the character that starts a single-line comment or {@code null}. The default is {@code '#'}. + * @see ParserSpec#atFileCommentChar() + * @since 3.5 */ + public Character getAtFileCommentChar() { return getCommandSpec().parser().atFileCommentChar(); } + + /** Sets the character that starts a single-line comment or {@code null} if all content of argument files should + * be interpreted as arguments (without comments). + * If specified, all characters from the comment character to the end of the line are ignored. + * @param atFileCommentChar the character that starts a single-line comment or {@code null}. The default is {@code '#'}. + * @return this {@code CommandLine} object, to allow method chaining + * @see ParserSpec#atFileCommentChar(Character) + * @since 3.5 */ + public CommandLine setAtFileCommentChar(Character atFileCommentChar) { + getCommandSpec().parser().atFileCommentChar(atFileCommentChar); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setAtFileCommentChar(atFileCommentChar); + } + return this; + } + + /** Returns whether to use a simplified argument file format that is compatible with JCommander. + * In this format, every line (except empty lines and comment lines) + * is interpreted as a single argument. Arguments containing whitespace do not need to be quoted. + * When system property {@code "acrostics.useSimplifiedAtFiles"} is defined, the system property value overrides the programmatically set value. + * @return whether to use a simplified argument file format. The default is {@code false}. + * @see ParserSpec#useSimplifiedAtFiles() + * @since 3.9 */ + public boolean isUseSimplifiedAtFiles() { return getCommandSpec().parser().useSimplifiedAtFiles(); } + + /** Sets whether to use a simplified argument file format that is compatible with JCommander. + * In this format, every line (except empty lines and comment lines) + * is interpreted as a single argument. Arguments containing whitespace do not need to be quoted. + * When system property {@code "acrostics.useSimplifiedAtFiles"} is defined, the system property value overrides the programmatically set value. + * @param simplifiedAtFiles whether to use a simplified argument file format. The default is {@code false}. + * @return this {@code CommandLine} object, to allow method chaining + * @see ParserSpec#useSimplifiedAtFiles(boolean) + * @since 3.9 */ + public CommandLine setUseSimplifiedAtFiles(boolean simplifiedAtFiles) { + getCommandSpec().parser().useSimplifiedAtFiles(simplifiedAtFiles); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setUseSimplifiedAtFiles(simplifiedAtFiles); + } + return this; + } + /** Returns the {@code INegatableOptionTransformer} used to create the negative form of {@linkplain Option#negatable() negatable} options. + * By default this returns the result of {@link RegexTransformer#createDefault()}. + * @return the {@code INegatableOptionTransformer} used to create negative option names. + * @see Option#negatable() + * @see CommandSpec#negatableOptionTransformer() + * @since 4.0 */ + public INegatableOptionTransformer getNegatableOptionTransformer() { return getCommandSpec().negatableOptionTransformer(); } + + /** Sets the {@code INegatableOptionTransformer} used to create the negative form of {@linkplain Option#negatable() negatable} options. + *

The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its + * subcommands and nested sub-subcommands at the moment this method is called. Subcommands added + * later will have the default setting. To ensure a setting is applied to all + * subcommands, call the setter last, after adding subcommands.

+ * Note that {@link CommandLine#setOptionsCaseInsensitive} will also change the case sensitivity of {@linkplain Option#negatable() negatable} options: + * any custom {@link INegatableOptionTransformer} that was previously installed will be replaced by the case-insensitive + * version of the default transformer. To ensure your custom transformer is used, install it last, after changing case sensitivity. + * @param transformer the {@code INegatableOptionTransformer} used to create negative option names. + * @return this {@code CommandLine} object, to allow method chaining + * @see Option#negatable() + * @see CommandSpec#negatableOptionTransformer(CommandLine.INegatableOptionTransformer) + * @since 4.0 */ + public CommandLine setNegatableOptionTransformer(INegatableOptionTransformer transformer) { + getCommandSpec().negatableOptionTransformer(transformer); + for (CommandLine command : getCommandSpec().subcommands().values()) { + command.setNegatableOptionTransformer(transformer); + } + return this; + } + private static boolean empty(String str) { return str == null || str.trim().length() == 0; } + private static boolean empty(Object[] array) { return array == null || array.length == 0; } + private static String str(String[] arr, int i) { return (arr == null || arr.length <= i) ? "" : arr[i]; } + private static boolean isBoolean(Class[] types) { return isBoolean(types[0]) || (isOptional(types[0]) && isBoolean(types[1])); } + private static boolean isBoolean(Class type) { return type == Boolean.class || type == Boolean.TYPE; } + private static CommandLine toCommandLine(Object obj, IFactory factory) { return obj instanceof CommandLine ? (CommandLine) obj : new CommandLine(obj, factory, false);} + private static boolean isMultiValue(Class cls) { return (cls.isArray() && cls != char[].class) || Collection.class.isAssignableFrom(cls) || Map.class.isAssignableFrom(cls); } + private static boolean isOptional(Class cls) { return cls != null && "java.util.Optional".equals(cls.getName()); } // #1108 + private static Object getOptionalEmpty() throws Exception { + return Class.forName("java.util.Optional").getMethod("empty").invoke(null); + } + private static Object getOptionalOfNullable(Object newValue) throws Exception { + return Class.forName("java.util.Optional").getMethod("ofNullable", Object.class).invoke(null, newValue); + } + private static String format(String formatString, Object... params) { + try { + return formatString == null ? "" : String.format(formatString, params); + } catch (IllegalFormatException ex) { + CommandLine.tracer().warn("Could not format '%s' (Underlying error: %s). " + + "Using raw String: '%%n' format strings have not been replaced with newlines. " + + "Please ensure to escape '%%' characters with another '%%'.", formatString, ex.getMessage()); + return formatString; + } + } + private static Map mapOf(String key, Object value, Object... other) { + LinkedHashMap result = new LinkedHashMap(); + result.put(key, value); + for (int i = 0; i < other.length - 1; i += 2) { + result.put(String.valueOf(other[i]), other[i + 1]); + } + return result; + } + + private static class NoCompletionCandidates implements Iterable { + public Iterator iterator() { throw new UnsupportedOperationException(); } + } + /** Specifies the scope of the element. + * @since 4.3 */ + public enum ScopeType { + /** The element only exists in the current command. */ + LOCAL, + /** The element exists in the command where the element is defined and all descendants (subcommands, sub-subcommands, etc.). */ + INHERIT, + } + /** + *

+ * Annotate fields in your class with {@code @Option} and acrostics will initialize these fields when matching + * arguments are specified on the command line. In the case of command methods (annotated with {@code @Command}), + * command options can be defined by annotating method parameters with {@code @Option}. + *

+ * Command class example: + *

+ *
+     * import static acrostics.CommandLine.*;
+     *
+     * public class MyClass {
+     *     @Parameters(description = "Any number of input files")
+     *     private List<File> files = new ArrayList<File>();
+     *
+     *     @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
+     *     private File outputFile;
+     *
+     *     @Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
+     *     private boolean[] verbose;
+     *
+     *     @Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
+     *     private boolean help;
+     * }
+     * 
+ *

+ * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a + * {@code ParameterException} is thrown. + *

+ */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) + public @interface Option { + /** Special value that can be used in some annotation attributes to designate {@code null}. + * @see Option#defaultValue() + * @see Option#fallbackValue() + * @see Option#mapFallbackValue() + * @since 4.6 */ + public static final String NULL_VALUE = ArgSpec.NULL_VALUE; + /** + * One or more option names. At least one option name is required. + *

+ * Different environments have different conventions for naming options, but usually options have a prefix + * that sets them apart from parameters. + * Picocli supports all of the below styles. The default separator is {@code '='}, but this can be configured. + *

+ * *nix + *

+ * In Unix and Linux, options have a short (single-character) name, a long name or both. + * Short options + * (POSIX + * style are single-character and are preceded by the {@code '-'} character, e.g., {@code `-v'}. + * GNU-style long + * (or mnemonic) options start with two dashes in a row, e.g., {@code `--file'}. + *

Picocli supports the POSIX convention that short options can be grouped, with the last option + * optionally taking a parameter, which may be attached to the option name or separated by a space or + * a {@code '='} character. The below examples are all equivalent: + *

+         * -xvfFILE
+         * -xvf FILE
+         * -xvf=FILE
+         * -xv --file FILE
+         * -xv --file=FILE
+         * -x -v --file FILE
+         * -x -v --file=FILE
+         * 

+ * DOS + *

+ * DOS options mostly have upper case single-character names and start with a single slash {@code '/'} character. + * Option parameters are separated by a {@code ':'} character. Options cannot be grouped together but + * must be specified separately. For example: + *

+         * DIR /S /A:D /T:C
+         * 

+ * PowerShell + *

+ * Windows PowerShell options generally are a word preceded by a single {@code '-'} character, e.g., {@code `-Help'}. + * Option parameters are separated by a space or by a {@code ':'} character. + *

+ * @return one or more option names + */ + String[] names(); + + /** + * Indicates whether this option is required. By default this is false. + *

If an option is required, but a user invokes the program without specifying the required option, + * a {@link MissingParameterException} is thrown from the {@link #parse(String...)} method.

+ *

Required options that are part of a {@linkplain ArgGroup group} are required within the group, not required within the command: + * the group's {@linkplain ArgGroup#multiplicity() multiplicity} determines whether the group itself is required or optional.

+ * @return whether this option is required + */ + boolean required() default false; + + /** + *

This should rarely be used: the recommended attributes are {@link #usageHelp() usageHelp} and {@link #versionHelp() versionHelp}. + *

+ * Only set {@code help=true} when this option should disable validation of the remaining + * arguments, and no error message should be generated for missing required options. + *

+ * This is useful for custom help options that are in addition to the standard help and + * version options. For example if your application has many hidden options or + * subcommands, and there is a custom help option like {@code --detailed-help} that prints + * the usage help message for these hidden options and subcommands. + *

+ *

Note:

+ *

+ * Use the {@link #usageHelp() usageHelp} for "normal" help options (like {@code -h} and {@code --help} on unix, + * {@code -?} and {@code -Help} on Windows) + * and use {@link #versionHelp() versionHelp} for "normal" version help ({@code -V} and {@code --version} on unix, + * {@code -Version} on Windows): + * acrostics has built-in logic so that options with {@code usageHelp=true} or {@code versionHelp=true} + * will automatically cause the requested help message to be printed in applications + * that use the {@link #execute(String...)} method, without any code in the application. + *

+ * Note that there is no such automatic help printing for options with {@code help=true}; + * applications need to check whether the end user specified this option and take appropriate action + * in the business logic of the application. + *

+ * @return whether this option disables validation of the other arguments + */ + boolean help() default false; + + /** + * Set {@code usageHelp=true} for the {@code --help} option that triggers display of the usage help message. + * The convenience methods {@code Commandline.call}, + * {@code Commandline.run}, and {@code Commandline.parseWithHandler(s)} will automatically print usage help + * when an option with {@code usageHelp=true} was specified on the command line. + *

+ * By default, all options and positional parameters are included in the usage help message + * except when explicitly marked {@linkplain #hidden() hidden}. + *

+ * If this option is specified on the command line, acrostics will not validate the remaining arguments (so no "missing required + * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}. + *

+ * Alternatively, consider annotating your command with {@linkplain Command#mixinStandardHelpOptions() @Command(mixinStandardHelpOptions = true)}. + *

+ * @return whether this option allows the user to request usage help + * @since 0.9.8 + * @see #hidden() + * @see #run(Runnable, String...) + * @see #call(Callable, String...) + * @see #parseWithHandler(IParseResultHandler2, String[]) + * @see #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) + */ + boolean usageHelp() default false; + + /** + * Set {@code versionHelp=true} for the {@code --version} option that triggers display of the version information. + * The convenience methods {@code Commandline.call}, + * {@code Commandline.run}, and {@code Commandline.parseWithHandler(s)} will automatically print version information + * when an option with {@code versionHelp=true} was specified on the command line. + *

+ * The version information string is obtained from the command's {@linkplain Command#version() version} annotation + * or from the {@linkplain Command#versionProvider() version provider}. + *

+ * If this option is specified on the command line, acrostics will not validate the remaining arguments (so no "missing required + * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}. + *

+ * Alternatively, consider annotating your command with {@linkplain Command#mixinStandardHelpOptions() @Command(mixinStandardHelpOptions = true)}. + *

+ * @return whether this option allows the user to request version information + * @since 0.9.8 + * @see #hidden() + * @see #run(Runnable, String...) + * @see #call(Callable, String...) + * @see #parseWithHandler(IParseResultHandler2, String[]) + * @see #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) + */ + boolean versionHelp() default false; + + /** + * Description of this option, used when generating the usage documentation. Each element of the array is rendered on a separate line. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}. + *

+ * The description may contain variables that are rendered when help is requested. + * The string {@code ${DEFAULT-VALUE}} is replaced with the default value of the option. This is regardless of + * the command's {@link Command#showDefaultValues() showDefaultValues} setting or the option's {@link #showDefaultValue() showDefaultValue} setting. + * The string {@code ${COMPLETION-CANDIDATES}} is replaced with the completion candidates generated by + * {@link #completionCandidates()} in the description for this option. + * Also, embedded {@code %n} newline markers are converted to actual newlines. + *

+ * @return the description of this option + * @see Variable Interpolation section of the user manual + */ + String[] description() default {}; + + /** + * Specifies the minimum number of required parameters and the maximum number of accepted parameters. + * If an option declares a positive arity, and the user specifies an insufficient number of parameters on the + * command line, a {@link MissingParameterException} is thrown by the {@link #parse(String...)} method. + *

+ * In many cases acrostics can deduce the number of required parameters from the field's type. + * By default, flags (boolean options) have arity "0..1", + * and single-valued type fields (String, int, Integer, double, Double, File, Date, etc) have arity one. + * Generally, fields with types that cannot hold multiple values can omit the {@code arity} attribute. + *

+ * Fields used to capture options with arity two or higher should have a type that can hold multiple values, + * like arrays or Collections. See {@link #type()} for strongly-typed Collection fields. + *

+ * For example, if an option has 2 required parameters and any number of optional parameters, + * specify {@code @Option(names = "-example", arity = "2..*")}. + *

+ * A note on boolean options + *

+ * By default acrostics allows boolean options (also called "flags" or "switches") to have an optional parameter, + * which must be either "true" or "false" (lowercase, other values are rejected). + * You can make a boolean option take a required parameter by annotating your field with {@code arity="1"}. + * For example:

+ *
@Option(names = "-v", arity = "1") boolean verbose;
+ *

+ * Because this boolean field is defined with arity 1, the user must specify either {@code -v false} + * or {@code -v true} + * on the command line, or a {@link MissingParameterException} is thrown by the {@link #parse(String...)} + * method. + *

+ * To remove the optional parameter, define the field with {@code arity = "0"}. + * For example:

+ *
@Option(names="-v", arity="0") boolean verbose;
+ *

This will reject any of the below:

+ *
+         * -v true
+         * -v false
+         * 
+ * @return how many arguments this option requires + */ + String arity() default ""; + + /** + * Specify a {@code paramLabel} for the option parameter to be used in the usage help message. If omitted, + * acrostics uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example: + *
class Example {
+         *     @Option(names = {"-o", "--output"}, paramLabel="FILE", description="path of the output file")
+         *     private File out;
+         *     @Option(names = {"-j", "--jobs"}, arity="0..1", description="Allow N jobs at once; infinite jobs with no arg.")
+         *     private int maxJobs = -1;
+         * }
+ *

By default, the above gives a usage help message like the following:

+         * Usage: <main class> [OPTIONS]
+         * -o, --output FILE       path of the output file
+         * -j, --jobs [<maxJobs>]  Allow N jobs at once; infinite jobs with no arg.
+         * 
+ * @return name of the option parameter used in the usage help message + */ + String paramLabel() default ""; + + /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed. + * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters + * if the value is optional and followed by ellipses ("...") when multiple values can be specified. + * @since 3.6.0 */ + boolean hideParamSyntax() default false; + + /**

+ * Optionally specify a {@code type} to control exactly what Class the option parameter should be converted + * to. This may be useful when the field type is an interface or an abstract class. For example, a field can + * be declared to have type {@code java.lang.Number}, and annotating {@code @Option(type=Short.class)} + * ensures that the option parameter value is converted to a {@code Short} before setting the field value. + *

+ * For array fields whose component type is an interface or abstract class, specify the concrete component type. + * For example, a field with type {@code Number[]} may be annotated with {@code @Option(type=Short.class)} + * to ensure that option parameter values are converted to {@code Short} before adding an element to the array. + *

+ * Picocli will use the {@link ITypeConverter} that is + * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert + * the raw String values before modifying the field value. + *

+ * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields, + * but starting from 2.0 acrostics will infer the component type from the generic type's type arguments. + * For example, for a field of type {@code Map} acrostics will know the option parameter + * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit} + * enum value, and the value should be converted to a {@code Long}. No {@code @Option(type=...)} type attribute + * is required for this. For generic types with wildcards, acrostics will take the specified upper or lower bound + * as the Class to convert to, unless the {@code @Option} annotation specifies an explicit {@code type} attribute. + *

+ * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings, + * or if the generic type's type arguments are interfaces or abstract classes, you may + * specify a {@code type} attribute to control the Class that the option parameter should be converted to. + * @return the type(s) to convert the raw String values + */ + Class[] type() default {}; + + /** + * Optionally specify one or more {@link ITypeConverter} classes to use to convert the command line argument into + * a strongly typed value (or key-value pair for map fields). This is useful when a particular field should + * use a custom conversion that is different from the normal conversion for the field's type. + *

For example, for a specific field you may want to use a converter that maps the constant names defined + * in {@link java.sql.Types java.sql.Types} to the {@code int} value of these constants, but any other {@code int} fields should + * not be affected by this and should continue to use the standard int converter that parses numeric values.

+ * @return the type converter(s) to use to convert String values to strongly typed values for this field + * @see CommandLine#registerConverter(Class, ITypeConverter) + */ + Class>[] converter() default {}; + + /** + * Specify a regular expression to use to split option parameter values before applying them to the field. + * All elements resulting from the split are added to the array or Collection. Previously ignored for single-value fields, + * from acrostics 4.0 a {@code split} regex can only be specified on multi-value options and positional parameters. + * @return a regular expression to split option parameter values or {@code ""} if the value should not be split + * @see String#split(String) + */ + String split() default ""; + + /** + * Specify the string to display for the {@link #split split} regular expression in the usage help synopsis. + * @since 4.3 */ + String splitSynopsisLabel() default ""; + + /** + * Set {@code hidden=true} if this option should not be included in the usage help message. + * @return whether this option should be excluded from the usage documentation + */ + boolean hidden() default false; + + /** Returns the default value of this option, before splitting and type conversion. + *

To get a {@code null} default value, omit specifying a default value or use the special value {@link Option#NULL_VALUE} - + * for options of type {@code Optional} that will result in the {@code Optional.empty()} + * value being assigned when the option is not specified on the command line.

+ * @return a String that (after type conversion) will be used as the value for this option if the option was not specified on the command line + * @see #fallbackValue() + * @since 3.2 */ + String defaultValue() default "__no_default_value__"; + + /** Use this attribute to control for a specific option whether its default value should be shown in the usage + * help message. If not specified, the default value is only shown when the {@link Command#showDefaultValues()} + * is set {@code true} on the command. Use this attribute to specify whether the default value + * for this specific option should always be shown or never be shown, regardless of the command setting. + *

Note that acrostics 3.2 allows {@linkplain #description() embedding default values} by specifying the variable + * {@code ${DEFAULT-VALUE}} anywhere in the description that ignores this setting.

+ * @return whether this option's default value should be shown in the usage help message + */ + Help.Visibility showDefaultValue() default Help.Visibility.ON_DEMAND; + + /** Use this attribute to specify an {@code Iterable} class that generates completion candidates for this option. + * For map fields, completion candidates should be in {@code key=value} form. + *

+ * Completion candidates are used in bash completion scripts generated by the {@code acrostics.AutoComplete} class. + * Bash has special completion options to generate file names and host names, and the bash completion scripts + * generated by {@code AutoComplete} delegate to these bash built-ins for {@code @Options} whose {@code type} is + * {@code java.io.File}, {@code java.nio.file.Path} or {@code java.net.InetAddress}. + *

+ * For {@code @Options} whose {@code type} is a Java {@code enum}, {@code AutoComplete} can generate completion + * candidates from the type. For other types, use this attribute to specify completion candidates. + *

+ * + * @return a class whose instances can iterate over the completion candidates for this option + * @see acrostics.CommandLine.IFactory + * @since 3.2 */ + Class> completionCandidates() default NoCompletionCandidates.class; + + /** + * Set {@code interactive=true} to make this option prompt the end user for a value (like a password). + * Only supported for single-value options and {@code char[]} arrays (no collections, maps or other array types). + * When running on Java 6 or greater and {@link Option#echo() echo = false} (the default), + * this will use the {@link Console#readPassword()} API to get a value without echoing input to the console, + * otherwise it will simply read a value from {@code System.in}. + *

+ * For passwords, best security practice is to use type {@code char[]} instead of {@code String}, and to to null out the array after use. + *

+ * When defined with {@code arity = "0..1"}, the option can also take a value from the command line. + * (The user will still be prompted if no option parameter was specified on the command line.) + * This is useful for commands that need to be run interactively as well as in batch mode. + *

+ * @return whether this option prompts the end user for a value to be entered on the command line + * @since 3.5 + */ + boolean interactive() default false; + + /** Use this attribute to control whether user input for an interactive option is echoed to the console or not. + * If {@code echo = true}, the user input is echoed to the console. + * This attribute is ignored when {@code interactive = false} (the default). + * @return whether the user input for an interactive option should be echoed to the console or not + * @see OptionSpec#echo() + * @since 4.6 */ + boolean echo() default false; + + /** Use this attribute to customize the text displayed to the end user for an interactive option when asking for user input. + * When omitted, the displayed text is derived from the option name and the first description line. + * This attribute is ignored when {@code interactive = false} (the default). + * @return the text to display to the end user for an interactive option when asking for user input + * @see OptionSpec#prompt() + * @since 4.6 */ + String prompt() default ""; + + /** ResourceBundle key for this option. If not specified, (and a ResourceBundle {@linkplain Command#resourceBundle() exists for this command}) an attempt + * is made to find the option description using any of the option names (without leading hyphens) as key. + * @see OptionSpec#description() + * @since 3.6 + */ + String descriptionKey() default ""; + + /** + * When {@link Command#sortOptions() @Command(sortOptions = false)} is specified, this attribute can be used to control the order in which options are listed in the usage help message. + * When {@link Command#sortSynopsis() @Command(sortSynopsis = false)} is specified, this attribute controls the order in which options appear in the synopsis of the usage help message. + * @return the position in the options list at which this option should be shown. Options with a lower number are shown before options with a higher number. Gaps are allowed. + * @since 3.9 + */ + int order() default -1; + + /** (Only for boolean options): set this to automatically add a negative version for this boolean option. + * For example, for a {@code --force} option the negative version would be {@code --no-force}, + * and for a {@code -XX:+PrintGCDetails} option, the negative version would be {@code -XX:-PrintGCDetails}. + * The synopsis would show {@code --[no-]force} and {@code -XX:(+|-)PrintGCDetails}, respectively. + *

The form of the negative name can be customized by modifying the regular expressions + * used by {@linkplain RegexTransformer#createDefault() default}, or by replacing the default + * {@link INegatableOptionTransformer} with a custom implementation entirely.

+ *

Negative option names used to parse the command line are collected when the command is constructed + * (so any variables in the option names will be resolved at that time). + * Documentation strings for negatable options are generated on demand when the usage help message is shown.

+ * @see CommandLine#getNegatableOptionTransformer() + * @see CommandLine#setNegatableOptionTransformer(INegatableOptionTransformer) + * @since 4.0 */ + boolean negatable() default false; + + /** Determines on which command(s) this option exists: on this command only (the default), or + * whether this is a "global" option that is applied to this command and all subcommands, sub-subcommands, etc. + * @since 4.3 + */ + ScopeType scope() default ScopeType.LOCAL; + /** + * For options with an optional parameter (for example, {@code arity = "0..1"}), this value is assigned to the annotated element + * if the option is specified on the command line without an option parameter. + *

+ * This is different from the {@link #defaultValue()}, which is assigned if the option is not specified at all on the command line. + *

+ * Using a {@code fallbackValue} allows applications to distinguish between

+ *
    + *
  • option was not specified on the command line (default value assigned)
  • + *
  • option was specified without parameter on the command line (fallback value assigned)
  • + *
  • option was specified with parameter on the command line (command line argument value assigned)
  • + *
+ *

This is useful to define options that can function as a boolean "switch" + * and optionally allow users to provide a (strongly typed) extra parameter value. + *

+ *

Use the special value {@link Option#NULL_VALUE} to specify {@code null} - + * for options of type {@code Optional} that will result in the {@code Optional.empty()} + * value being assigned when the option name is specified without a parameter on the command line.

+ * @see OptionSpec#fallbackValue() + * @since 4.0 */ + String fallbackValue() default ""; + + /** For options of type Map, setting the {@code mapFallbackValue} to any value allows end user + * to specify key-only parameters for this option. For example, {@code -Dkey} instead of {@code -Dkey=value}. + *

The value specified in this annotation is the value that is put into the Map for the user-specified key. + * Use the special value {@link Option#NULL_VALUE} to specify {@code null} - + * for maps of type {@code Map>} that will result in {@code Optional.empty()} + * values in the map when only the key is specified.

+ *

If no {@code mapFallbackValue} is set, key-only Map parameters like {@code -Dkey} + * are considered invalid user input and cause a {@link ParameterException} to be thrown.

+ * @see ArgSpec#mapFallbackValue() + * @since 4.6 */ + String mapFallbackValue() default ArgSpec.UNSPECIFIED; + + /** + * Optionally specify a custom {@code IParameterConsumer} to temporarily suspend acrostics's parsing logic + * and process one or more command line arguments in a custom manner. + * This may be useful when passing arguments through to another program. + * @since 4.0 */ + Class parameterConsumer() default NullParameterConsumer.class; + + /** Returns the preprocessor for this option. + * @see IParameterPreprocessor + * @since 4.6 */ + Class preprocessor() default NoOpParameterPreprocessor.class; + } + /** + *

+ * Fields annotated with {@code @Parameters} will be initialized with positional parameters. By specifying the + * {@link #index()} attribute you can pick the exact position or a range of positional parameters to apply. If no + * index is specified, the field will get all positional parameters (and so it should be an array or a collection). + *

+ * In the case of command methods (annotated with {@code @Command}), method parameters may be annotated with {@code @Parameters}, + * but are are considered positional parameters by default, unless they are annotated with {@code @Option}. + *

+ * Command class example: + *

+ *
+     * import static acrostics.CommandLine.*;
+     *
+     * public class MyCalcParameters {
+     *     @Parameters(description = "Any number of input numbers")
+     *     private List<BigDecimal> files = new ArrayList<BigDecimal>();
+     *
+     *     @Option(names = { "-h", "--help" }, usageHelp = true, description = "Display this help and exit")
+     *     private boolean help;
+     * }
+     * 

+ * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a {@code ParameterException} + * is thrown.

+ */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) + public @interface Parameters { + /** Special value that can be used in some annotation attributes to designate {@code null}. + * @see Parameters#defaultValue() + * @see Parameters#mapFallbackValue() + * @since 4.6 */ + public static final String NULL_VALUE = ArgSpec.NULL_VALUE; + /** Specify an index ("0", or "1", etc.) to pick which of the command line arguments should be assigned to this + * field. For array or Collection fields, you can also specify an index range ("0..3", or "2..*", etc.) to assign + * a subset of the command line arguments to this field. The default is "*", meaning all command line arguments. + * @return an index or range specifying which of the command line arguments should be assigned to this field + */ + String index() default ""; + + /** Description of the parameter(s), used when generating the usage documentation. Each element of the array is rendered on a separate line. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}. + *

+ * The description may contain variables that are rendered when help is requested. + * The string {@code ${DEFAULT-VALUE}} is replaced with the default value of the positional parameter. This is regardless of + * the command's {@link Command#showDefaultValues() showDefaultValues} setting or the positional parameter's {@link #showDefaultValue() showDefaultValue} setting. + * The string {@code ${COMPLETION-CANDIDATES}} is replaced with the completion candidates generated by + * {@link #completionCandidates()} in the description for this positional parameter. + * Also, embedded {@code %n} newline markers are converted to actual newlines. + *

+ * @return the description of the parameter(s) + * @see Variable Interpolation section of the user manual + */ + String[] description() default {}; + + /** + * Specifies the minimum number of required parameters and the maximum number of accepted parameters. If a + * positive arity is declared, and the user specifies an insufficient number of parameters on the command line, + * {@link MissingParameterException} is thrown by the {@link #parse(String...)} method. + *

The default depends on the type of the parameter: booleans require no parameters, arrays and Collections + * accept zero to any number of parameters, and any other type accepts one parameter.

+ *

For single-value parameters, setting {@code arity = "0..1"} makes a positional parameter optional, while setting {@code arity = "1"} makes it required.

+ *

Required parameters that are part of a {@linkplain ArgGroup group} are required within the group, not required within the command: + * the group's {@linkplain ArgGroup#multiplicity() multiplicity} determines whether the group itself is required or optional.

+ * @return the range of minimum and maximum parameters accepted by this command + */ + String arity() default ""; + + /** + * Specify a {@code paramLabel} for the parameter to be used in the usage help message. If omitted, + * acrostics uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example: + *
class Example {
+         *     @Parameters(paramLabel="FILE", description="path of the input FILE(s)")
+         *     private File[] inputFiles;
+         * }
+ *

By default, the above gives a usage help message like the following:

+         * Usage: <main class> [FILE...]
+         * [FILE...]       path of the input FILE(s)
+         * 
+ * @return name of the positional parameter used in the usage help message + */ + String paramLabel() default ""; + + /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed. + * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters + * if the value is optional and followed by ellipses ("...") when multiple values can be specified. + * @since 3.6.0 */ + boolean hideParamSyntax() default false; + + /** + *

+ * Optionally specify a {@code type} to control exactly what Class the positional parameter should be converted + * to. This may be useful when the field type is an interface or an abstract class. For example, a field can + * be declared to have type {@code java.lang.Number}, and annotating {@code @Parameters(type=Short.class)} + * ensures that the positional parameter value is converted to a {@code Short} before setting the field value. + *

+ * For array fields whose component type is an interface or abstract class, specify the concrete component type. + * For example, a field with type {@code Number[]} may be annotated with {@code @Parameters(type=Short.class)} + * to ensure that positional parameter values are converted to {@code Short} before adding an element to the array. + *

+ * Picocli will use the {@link ITypeConverter} that is + * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert + * the raw String values before modifying the field value. + *

+ * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields, + * but starting from 2.0 acrostics will infer the component type from the generic type's type arguments. + * For example, for a field of type {@code Map} acrostics will know the positional parameter + * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit} + * enum value, and the value should be converted to a {@code Long}. No {@code @Parameters(type=...)} type attribute + * is required for this. For generic types with wildcards, acrostics will take the specified upper or lower bound + * as the Class to convert to, unless the {@code @Parameters} annotation specifies an explicit {@code type} attribute. + *

+ * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings, + * or if the generic type's type arguments are interfaces or abstract classes, you may + * specify a {@code type} attribute to control the Class that the positional parameter should be converted to. + * @return the type(s) to convert the raw String values + */ + Class[] type() default {}; + + /** + * Optionally specify one or more {@link ITypeConverter} classes to use to convert the command line argument into + * a strongly typed value (or key-value pair for map fields). This is useful when a particular field should + * use a custom conversion that is different from the normal conversion for the field's type. + *

For example, for a specific field you may want to use a converter that maps the constant names defined + * in {@link java.sql.Types java.sql.Types} to the {@code int} value of these constants, but any other {@code int} fields should + * not be affected by this and should continue to use the standard int converter that parses numeric values.

+ * @return the type converter(s) to use to convert String values to strongly typed values for this field + * @see CommandLine#registerConverter(Class, ITypeConverter) + */ + Class>[] converter() default {}; + + /** + * Specify a regular expression to use to split positional parameter values before applying them to the field. + * All elements resulting from the split are added to the array or Collection. Previously ignored for single-value fields, + * from acrostics 4.0 a {@code split} regex can only be specified on multi-value options and positional parameters. + * @return a regular expression to split operand values or {@code ""} if the value should not be split + * @see String#split(String) + */ + String split() default ""; + + /** + * Specify a string to show the split option parameter values in usage + * @since 4.3 + */ + String splitSynopsisLabel() default ""; + + /** + * Set {@code hidden=true} if this parameter should not be included in the usage message. + * @return whether this parameter should be excluded from the usage message + */ + boolean hidden() default false; + + /** Returns the default value of this positional parameter, before splitting and type conversion. + *

To get a {@code null} default value, omit specifying a default value or use the special value {@link Parameters#NULL_VALUE} - + * for positional parameters of type {@code Optional} that will result in the {@code Optional.empty()} + * value being assigned when the positional parameters is not specified on the command line.

+ * @return a String that (after type conversion) will be used as the value for this positional parameter if no value was specified on the command line + * @since 3.2 */ + String defaultValue() default "__no_default_value__"; + + /** Use this attribute to control for a specific positional parameter whether its default value should be shown in the usage + * help message. If not specified, the default value is only shown when the {@link Command#showDefaultValues()} + * is set {@code true} on the command. Use this attribute to specify whether the default value + * for this specific positional parameter should always be shown or never be shown, regardless of the command setting. + *

Note that acrostics 3.2 allows {@linkplain #description() embedding default values} by specifying the variable + * {@code ${DEFAULT-VALUE}} anywhere in the description that ignores this setting.

+ * @return whether this positional parameter's default value should be shown in the usage help message + */ + Help.Visibility showDefaultValue() default Help.Visibility.ON_DEMAND; + + /** Use this attribute to specify an {@code Iterable} class that generates completion candidates for + * this positional parameter. For map fields, completion candidates should be in {@code key=value} form. + *

+ * Completion candidates are used in bash completion scripts generated by the {@code acrostics.AutoComplete} class. + * Unfortunately, {@code acrostics.AutoComplete} is not very good yet at generating completions for positional parameters. + *

+ * + * @return a class whose instances can iterate over the completion candidates for this positional parameter + * @see acrostics.CommandLine.IFactory + * @since 3.2 */ + Class> completionCandidates() default NoCompletionCandidates.class; + + /** + * Set {@code interactive=true} if this positional parameter will prompt the end user for a value (like a password). + * Only supported for single-value positional parameters (not arrays, collections or maps). + * When running on Java 6 or greater and {@link Option#echo() echo = false} (the default), + * this will use the {@link Console#readPassword()} API to get a value without echoing input to the console, + * otherwise it will simply read a value from {@code System.in}. + * @return whether this positional parameter prompts the end user for a value to be entered on the command line + * @since 3.5 + */ + boolean interactive() default false; + + /** Use this attribute to control whether user input for an interactive positional parameter is echoed to the console or not. + * If {@code echo = true}, the user input is echoed to the console. + * This attribute is ignored when {@code interactive = false} (the default). + * @return whether the user input for an interactive positional parameter should be echoed to the console or not + * @see PositionalParamSpec#echo() + * @since 4.6 */ + boolean echo() default false; + + /** Use this attribute to customize the text displayed to the end user for an interactive positional parameter when asking for user input. + * When omitted, the displayed text is derived from the positional parameter's + * position (index) and the first description line. + * This attribute is ignored when {@code interactive = false} (the default). + * @return the text to display to the end user for an interactive positional parameter when asking for user input + * @see PositionalParamSpec#prompt() + * @since 4.6 */ + String prompt() default ""; + + /** ResourceBundle key for this option. If not specified, (and a ResourceBundle {@linkplain Command#resourceBundle() exists for this command}) an attempt + * is made to find the positional parameter description using {@code paramLabel() + "[" + index() + "]"} as key. + * + * @see PositionalParamSpec#description() + * @since 3.6 + */ + String descriptionKey() default ""; + + /** Determines on which command(s) this positional parameter exists: on this command only (the default), or + * whether this is a "global" parameter that is applied to this command and all subcommands, sub-subcommands, etc. + * @since 4.3 + */ + ScopeType scope() default ScopeType.LOCAL; + /** + * Optionally specify a custom {@code IParameterConsumer} to temporarily suspend acrostics's parsing logic + * and process one or more command line arguments in a custom manner. + * @since 4.0 */ + Class parameterConsumer() default NullParameterConsumer.class; + + /** For positional parameters of type Map, setting the {@code mapFallbackValue} to any value allows end user + * to specify key-only parameters for this parameter. For example, {@code key} instead of {@code key=value}. + *

The value specified in this annotation is the value that is put into the Map for the user-specified key. + * Use the special value {@link Parameters#NULL_VALUE} to specify {@code null} - + * for maps of type {@code Map>} that will result in {@code Optional.empty()} + * values in the map when only the key is specified.

+ *

If no {@code mapFallbackValue} is set, key-only Map parameters like {@code -Dkey} + * are considered invalid user input and cause a {@link ParameterException} to be thrown.

+ * @see ArgSpec#mapFallbackValue() + * @since 4.6 */ + String mapFallbackValue() default ArgSpec.UNSPECIFIED; + + /** Returns the preprocessor for this positional parameter. + * @see IParameterPreprocessor + * @since 4.6 */ + Class preprocessor() default NoOpParameterPreprocessor.class; + } + + /** + *

+ * Fields annotated with {@code @ParentCommand} will be initialized with the parent command of the current subcommand. + * If the current command does not have a parent command, this annotation has no effect. + *

+ * Parent commands often define options that apply to all the subcommands. + * This annotation offers a convenient way to inject a reference to the parent command into a subcommand, so the + * subcommand can access its parent options. For example: + *

+     * @Command(name = "top", subcommands = Sub.class)
+     * class Top implements Runnable {
+     *
+     *     @Option(names = {"-d", "--directory"}, description = "this option applies to all subcommands")
+     *     File baseDirectory;
+     *
+     *     public void run() { System.out.println("Hello from top"); }
+     * }
+     *
+     * @Command(name = "sub")
+     * class Sub implements Runnable {
+     *
+     *     @ParentCommand
+     *     private Top parent;
+     *
+     *     public void run() {
+     *         System.out.println("Subcommand: parent command 'directory' is " + parent.baseDirectory);
+     *     }
+     * }
+     * 
+ * @since 2.2 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface ParentCommand { } + + /** + * Fields annotated with {@code @Unmatched} will be initialized with the list of unmatched command line arguments, if any. + * If this annotation is found, acrostics automatically sets {@linkplain CommandLine#setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} to {@code true}. + * @see CommandLine#isUnmatchedArgumentsAllowed() + * @since 3.0 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Unmatched { } + + /** + *

+ * Fields annotated with {@code @Mixin} are "expanded" into the current command: {@link Option @Option} and + * {@link Parameters @Parameters} in the mixin class are added to the options and positional parameters of this command. + * A {@link DuplicateOptionAnnotationsException} is thrown if any of the options in the mixin has the same name as + * an option in this command. + *

+ * The {@code Mixin} annotation provides a way to reuse common options and parameters without subclassing. For example: + *

+     * @Command(name="HelloWorld")
+     * class HelloWorld implements Runnable {
+     *
+     *     // adds the --help and --version options to this command
+     *     @Mixin
+     *     private HelpOptions options = new HelpOptions();
+     *
+     *     @Option(names = {"-u", "--userName"}, required = true, description = "The user name")
+     *     String userName;
+     *
+     *     public void run() { System.out.println("Hello, " + userName); }
+     * }
+     *
+     * // Common reusable help options.
+     * class HelpOptions {
+     *
+     *     @Option(names = { "-h", "--help"}, usageHelp = true, description = "Display this help and exit")
+     *     private boolean help;
+     *
+     *     @Option(names = { "-V", "--version"}, versionHelp = true, description = "Display version info and exit")
+     *     private boolean versionHelp;
+     * }
+     * 
+ * @since 3.0 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.PARAMETER}) + public @interface Mixin { + /** Optionally specify a name that the mixin object can be retrieved with from the {@code CommandSpec}. + * If not specified the name of the annotated field is used. + * @return a String to register the mixin object with, or an empty String if the name of the annotated field should be used */ + String name() default ""; + } + /** + * Fields annotated with {@code @Spec} will be initialized with the {@code CommandSpec} for the command the field is part of. Example usage: + *
+     * class InjectSpecExample implements Runnable {
+     *     @Spec CommandSpec commandSpec;
+     *     //...
+     *     public void run() {
+     *         // do something with the injected objects
+     *     }
+     * }
+     * 
+ * @since 3.2 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.METHOD}) + public @interface Spec { + /** Identifies what kind of {@code CommandSpec} should be injected. + * @since 4.3.0 */ + enum Target { + /** Injects the {@code CommandSpec} of the command where this {@code @Spec}-annotated program element is declared. */ + SELF, + /** Injects the {@code CommandSpec} of the "mixee" command that receives the options and other command elements defined here, + * or {@code null} if this commands is not {@linkplain Mixin mixed into} another command. + * The "mixee" command has a {@code @Mixin}-annotated program element with the type of the class where this {@code @Spec}-annotated program element is declared. */ + MIXEE} + + /** Whether to inject the {@code CommandSpec} of this command (the default) or the {@code CommandSpec} + * of the "mixee" command that receives the options and other command elements defined here. + * @see Mixin + * @since 4.3.0 */ + Target value() default Target.SELF; + } + + /** + *

Annotate your class with {@code @Command} when you want more control over the format of the generated help + * message. From 3.6, methods can also be annotated with {@code @Command}, where the method parameters define the + * command options and positional parameters. + *

+     * @Command(name              = "Encrypt", mixinStandardHelpOptions = true,
+     *        description         = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
+     *        version             = "Encrypt version 1.0",
+     *        footer              = "Copyright (c) 2017",
+     *        exitCodeListHeading = "Exit Codes:%n",
+     *        exitCodeList        = { " 0:Successful program execution.",
+     *                                "64:Invalid input: an unknown option or invalid parameter was specified.",
+     *                                "70:Execution exception: an exception occurred while executing the business logic."}
+     *        )
+     * public class Encrypt {
+     *     @Parameters(paramLabel = "FILE", description = "Any number of input files")
+     *     private List<File> files = new ArrayList<File>();
+     *
+     *     @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
+     *     private File outputFile;
+     *
+     *     @Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
+     *     private boolean[] verbose;
+     * }
+ *

+ * The structure of a help message looks like this: + *

    + *
  • [header]
  • + *
  • [synopsis]: {@code Usage: [OPTIONS] [FILE...]}
  • + *
  • [description]
  • + *
  • [parameter list]: {@code [FILE...] Any number of input files}
  • + *
  • [option list]: {@code -h, --help prints this help message and exits}
  • + *
  • [exit code list]
  • + *
  • [footer]
  • + *
*/ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.LOCAL_VARIABLE, ElementType.FIELD, ElementType.PACKAGE, ElementType.METHOD}) + public @interface Command { + /** Program name to show in the synopsis. If omitted, {@code "
"} is used. + * For {@linkplain #subcommands() declaratively added} subcommands, this attribute is also used + * by the parser to recognize subcommands in the command line arguments. + * @return the program name to show in the synopsis + * @see CommandSpec#name() + * @see Help#commandName() */ + String name() default CommandSpec.DEFAULT_COMMAND_NAME; + + /** Alternative command names by which this subcommand is recognized on the command line. + * @return one or more alternative command names + * @since 3.1 */ + String[] aliases() default {}; + + /** A list of classes to instantiate and register as subcommands. When registering subcommands declaratively + * like this, you don't need to call the {@link CommandLine#addSubcommand(String, Object)} method. For example, this: + *
+         * @Command(subcommands = {
+         *         GitStatus.class,
+         *         GitCommit.class,
+         *         GitBranch.class })
+         * public class Git { ... }
+         *
+         * CommandLine commandLine = new CommandLine(new Git());
+         * 
is equivalent to this: + *
+         * // alternative: programmatically add subcommands.
+         * // NOTE: in this case there should be no `subcommands` attribute on the @Command annotation.
+         * @Command public class Git { ... }
+         *
+         * CommandLine commandLine = new CommandLine(new Git())
+         *         .addSubcommand("status",   new GitStatus())
+         *         .addSubcommand("commit",   new GitCommit())
+         *         .addSubcommand("branch",   new GitBranch());
+         * 
+ * Applications may be interested in the following built-in commands in acrostics + * that can be used as subcommands: + *
    + *
  • {@link HelpCommand} - a {@code help} subcommand that prints help on the following or preceding command
  • + *
+ * @return the declaratively registered subcommands of this command, or an empty array if none + * @see CommandLine#addSubcommand(String, Object) + * @see HelpCommand + * @since 0.9.8 + */ + Class[] subcommands() default {}; + + /** Returns whether the subcommands of this command are repeatable, that is, whether such subcommands can + * occur multiple times and may be followed by sibling commands instead of only by child commands of the subcommand. + * @since 4.2 */ + boolean subcommandsRepeatable() default false; + + /** Specify whether methods annotated with {@code @Command} should be registered as subcommands of their + * enclosing {@code @Command} class. + * The default is {@code true}. For example: + *
+         * @Command
+         * public class Git {
+         *     @Command
+         *     void status() { ... }
+         * }
+         *
+         * CommandLine git = new CommandLine(new Git());
+         * 
is equivalent to this: + *
+         * // don't add command methods as subcommands automatically
+         * @Command(addMethodSubcommands = false)
+         * public class Git {
+         *     @Command
+         *     void status() { ... }
+         * }
+         *
+         * // add command methods as subcommands programmatically
+         * CommandLine git = new CommandLine(new Git());
+         * CommandLine status = new CommandLine(CommandLine.getCommandMethods(Git.class, "status").get(0));
+         * git.addSubcommand("status", status);
+         * 
+ * @return whether methods annotated with {@code @Command} should be registered as subcommands + * @see CommandLine#addSubcommand(String, Object) + * @see CommandLine#getCommandMethods(Class, String) + * @see CommandSpec#addMethodSubcommands() + * @since 3.6.0 */ + boolean addMethodSubcommands() default true; + + /** String that separates options from option parameters. Default is {@code "="}. Spaces are also accepted. + * @return the string that separates options from option parameters, used both when parsing and when generating usage help + * @see CommandLine#setSeparator(String) */ + String separator() default "="; + + /** Version information for this command, to print to the console when the user specifies an + * {@linkplain Option#versionHelp() option} to request version help. Each element of the array is rendered on a separate line. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ *

This is not part of the usage help message.

+ * + * @return a string or an array of strings with version information about this command (each string in the array is displayed on a separate line). + * @since 0.9.8 + * @see CommandLine#printVersionHelp(PrintStream) + */ + String[] version() default {}; + + /** Class that can provide version information dynamically at runtime. An implementation may return version + * information obtained from the JAR manifest, a properties file or some other source. + * @return a Class that can provide version information dynamically at runtime + * @since 2.2 */ + Class versionProvider() default NoVersionProvider.class; + + /** + * Adds the standard {@code -h} and {@code --help} {@linkplain Option#usageHelp() usageHelp} options and {@code -V} + * and {@code --version} {@linkplain Option#versionHelp() versionHelp} options to the options of this command. + *

+ * Note that if no {@link #version()} or {@link #versionProvider()} is specified, the {@code --version} option will not print anything. + *

+ * For {@linkplain #resourceBundle() internationalization}: the help option has {@code descriptionKey = "mixinStandardHelpOptions.help"}, + * and the version option has {@code descriptionKey = "mixinStandardHelpOptions.version"}. + *

+ * @return whether the auto-help mixin should be added to this command + * @since 3.0 */ + boolean mixinStandardHelpOptions() default false; + + /** Set this attribute to {@code true} if this subcommand is a help command, and required options and positional + * parameters of the parent command should not be validated. If a subcommand marked as {@code helpCommand} is + * specified on the command line, acrostics will not validate the parent arguments (so no "missing required + * option" errors) and the {@link CommandLine#printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} method will return {@code true}. + * @return {@code true} if this subcommand is a help command and acrostics should not check for missing required + * options and positional parameters on the parent command + * @since 3.0 */ + boolean helpCommand() default false; + + /** Set the heading preceding the header section. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return the heading preceding the header section + * @see UsageMessageSpec#headerHeading() + * @see Help#headerHeading(Object...) */ + String headerHeading() default ""; + + /** Optional summary description of the command, shown before the synopsis. Each element of the array is rendered on a separate line. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return summary description of the command + * @see UsageMessageSpec#header() + * @see Help#header(Object...) */ + String[] header() default {}; + + /** Set the heading preceding the synopsis text. The default heading is {@code "Usage: "} (without a line break between the heading and the synopsis text). + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return the heading preceding the synopsis text + * @see Help#synopsisHeading(Object...) */ + String synopsisHeading() default "Usage: "; + + /** Specify {@code true} to generate an abbreviated synopsis like {@code "
[OPTIONS] [PARAMETERS...] [COMMAND]"}. + * By default, a detailed synopsis with individual option names and parameters is generated. + * @return whether the synopsis should be abbreviated + * @see Help#abbreviatedSynopsis() + * @see Help#detailedSynopsis(int, Comparator, boolean) */ + boolean abbreviateSynopsis() default false; + + /** Specify one or more custom synopsis lines to display instead of an auto-generated synopsis. Each element of the array is rendered on a separate line. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return custom synopsis text to replace the auto-generated synopsis + * @see Help#customSynopsis(Object...) */ + String[] customSynopsis() default {}; + + /** + * Specify the String to show in the synopsis for the subcommands of this command. The default is + * {@code "[COMMAND]"}. Ignored if this command has no {@linkplain #subcommands() subcommands}. + * @since 4.0 + */ + String synopsisSubcommandLabel() default "[COMMAND]"; + + /** Set the heading preceding the description section. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return the heading preceding the description section + * @see Help#descriptionHeading(Object...) */ + String descriptionHeading() default ""; + + /** Optional text to display between the synopsis line(s) and the list of options. Each element of the array is rendered on a separate line. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return description of this command + * @see Help#description(Object...) */ + String[] description() default {}; + + /** Set the heading preceding the parameters list. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return the heading preceding the parameters list + * @see Help#parameterListHeading(Object...) */ + String parameterListHeading() default ""; + + /** Set the heading preceding the options list. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return the heading preceding the options list + * @see Help#optionListHeading(Object...) */ + String optionListHeading() default ""; + + /** Specify {@code false} to show Options in declaration order in the option list of the usage help message (or to sort options by their {@linkplain Option#order() order index} if set). + * Note that acrostics cannot reliably detect declaration order in commands that have both {@code @Option}-annotated methods and {@code @Option}-annotated fields. + * The default ({@code true}) is to sort alphabetically. + * @return whether options should be shown in alphabetic order. */ + boolean sortOptions() default true; + + /** Specify {@code false} to show options in declaration order in the synopsis of the usage help message (or to sort options by their {@linkplain Option#order() order index} if set). + * Note that acrostics cannot reliably detect declaration order in commands that have both {@code @Option}-annotated methods and {@code @Option}-annotated fields. + * The default ({@code true}) is to sort alphabetically. + * @return whether options in the synopsis should be shown in alphabetic order. + * @since 4.7.7-SNAPSHOT */ + boolean sortSynopsis() default true; + + /** Prefix required options with this character in the options list. The default is no marker: the synopsis + * indicates which options and parameters are required. + * @return the character to show in the options list to mark required options */ + char requiredOptionMarker() default ' '; + + /** Class that can provide default values dynamically at runtime. An implementation may return default + * value obtained from a configuration file like a properties file or some other source. + *

+ * Applications may be interested in the {@link PropertiesDefaultProvider} built-in default provider + * that allows end users to maintain their own default values for options and positional parameters, + * which may override the defaults that are hard-coded in the application. + *

+ * @return a Class that can provide default values dynamically at runtime + * @since 3.6 */ + Class defaultValueProvider() default NoDefaultProvider.class; + + /** Specify {@code true} to show default values in the description column of the options list (except for + * boolean options). False by default. + *

Note that acrostics 3.2 allows {@linkplain Option#description() embedding default values} anywhere in the + * option or positional parameter description that ignores this setting.

+ * @return whether the default values for options and parameters should be shown in the description column */ + boolean showDefaultValues() default false; + + /** Specify {@code true} to show a {@code [@...]} entry + * in the synopsis and parameter list of the usage help message. + * (The entry is not shown if {@linkplain CommandLine#isExpandAtFiles() expanding parameter files} is disabled.) + * @since 4.2 */ + boolean showAtFileInUsageHelp() default false; + + /** Specify {@code true} to show a {@code [--]} "End of options" entry + * in the synopsis and option list of the usage help message. + * @since 4.3 */ + boolean showEndOfOptionsDelimiterInUsageHelp() default false; + + /** Set the heading preceding the subcommands list. The default heading is {@code "Commands:%n"} (with a line break at the end). + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return the heading preceding the subcommands list + * @see Help#commandListHeading(Object...) */ + String commandListHeading() default "Commands:%n"; + + /** Set the heading preceding the footer section. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return the heading preceding the footer section + * @see Help#footerHeading(Object...) */ + String footerHeading() default ""; + + /** Optional text to display after the list of options. Each element of the array is rendered on a separate line. + *

May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.

+ * @return text to display after the list of options + * @see Help#footer(Object...) */ + String[] footer() default {}; + + /** + * Set {@code hidden=true} if this command should not be included in the list of commands in the usage help of the parent command. + * @return whether this command should be excluded from the usage message + * @since 3.0 + */ + boolean hidden() default false; + + /** Set the base name of the ResourceBundle to find option and positional parameters descriptions, as well as + * usage help message sections and section headings.

See {@link Messages} for more details and an example.

+ * @return the base name of the ResourceBundle for usage help strings + * @see ArgSpec#messages() + * @see UsageMessageSpec#messages() + * @see CommandSpec#resourceBundle() + * @see CommandLine#setResourceBundle(ResourceBundle) + * @since 3.6 + */ + String resourceBundle() default ""; + + /** Set the {@link UsageMessageSpec#width(int) usage help message width}. The default is 80. + * @see UsageMessageSpec#width() + * @since 3.7 + */ + int usageHelpWidth() default 80; + + /** If {@code true}, acrostics will attempt to detect the terminal width and adjust the usage help message accordingly. + * End users may enable this by setting system property {@code "acrostics.usage.width"} to {@code AUTO}, + * and may disable this by setting this system property to a {@linkplain UsageMessageSpec#width() numeric value}. + * This feature requires Java 7 or greater. The default is {@code false} + * @see UsageMessageSpec#autoWidth() + * @since 4.0 */ + boolean usageHelpAutoWidth() default false; + + /** Exit code for successful termination. {@value acrostics.CommandLine.ExitCode#OK} by default. + * @see #execute(String...) + * @since 4.0 */ + int exitCodeOnSuccess() default ExitCode.OK; + + /** Exit code for successful termination after printing usage help on user request. {@value acrostics.CommandLine.ExitCode#OK} by default. + * @see #execute(String...) + * @since 4.0 */ + int exitCodeOnUsageHelp() default ExitCode.OK; + + /** Exit code for successful termination after printing version help on user request. {@value acrostics.CommandLine.ExitCode#OK} by default. + * @see #execute(String...) + * @since 4.0 */ + int exitCodeOnVersionHelp() default ExitCode.OK; + + /** Exit code for command line usage error. {@value acrostics.CommandLine.ExitCode#USAGE} by default. + * @see #execute(String...) + * @since 4.0 */ + int exitCodeOnInvalidInput() default ExitCode.USAGE; + + /** Exit code signifying that an exception occurred when invoking the Runnable, Callable or Method user object of a command. + * {@value acrostics.CommandLine.ExitCode#SOFTWARE} by default. + * @see #execute(String...) + * @since 4.0 */ + int exitCodeOnExecutionException() default ExitCode.SOFTWARE; + + /** Set the heading preceding the exit codes section, may contain {@code "%n"} line separators. {@code ""} (empty string) by default. + * @see Help#exitCodeListHeading(Object...) + * @since 4.0 */ + String exitCodeListHeading() default ""; + + /** Set the values to be displayed in the exit codes section as a list of {@code "key:value"} pairs: + * keys are exit codes, values are descriptions. Descriptions may contain {@code "%n"} line separators. + *

For example:

+ *
+         * @Command(exitCodeListHeading = "Exit Codes:%n",
+         *          exitCodeList = { " 0:Successful program execution.",
+         *                           "64:Invalid input: an unknown option or invalid parameter was specified.",
+         *                           "70:Execution exception: an exception occurred while executing the business logic."})
+         * 
+ * @since 4.0 */ + String[] exitCodeList() default {}; + + /** Returns whether subcommands inherit their attributes from this parent command. + * @since 4.6 */ + ScopeType scope() default ScopeType.LOCAL; + + /** Returns the model transformer for this command. + * @since 4.6 */ + Class modelTransformer() default NoOpModelTransformer.class; + + /** Returns the preprocessor for this command. + * @see IParameterPreprocessor + * @since 4.6 */ + Class preprocessor() default NoOpParameterPreprocessor.class; + } + /** A {@code Command} may define one or more {@code ArgGroups}: a group of options, positional parameters or a mixture of the two. + * Groups can be used to: + *
    + *
  • define mutually exclusive arguments. By default, options and positional parameters + * in a group are mutually exclusive. This can be controlled with the {@link #exclusive() exclusive} attribute. + * Picocli will throw a {@link MutuallyExclusiveArgsException} if the command line contains multiple arguments that are mutually exclusive.
  • + *
  • define a set of arguments that must co-occur. Set {@link #exclusive() exclusive = false} + * to define a group of options and positional parameters that must always be specified together. + * Picocli will throw a {@link MissingParameterException MissingParameterException} if not all the options and positional parameters in a co-occurring group are specified together.
  • + *
  • create an option section in the usage help message. + * To be shown in the usage help message, a group needs to have a {@link #heading() heading} (which may come from a {@linkplain #headingKey() resource bundle}). + * Groups without a heading are only used for validation. + * Set {@link #validate() validate = false} for groups whose purpose is only to customize the usage help message.
  • + *
  • define composite repeating argument groups. Groups may contain other groups to create composite groups.
  • + *
+ *

Groups may be optional ({@code multiplicity = "0..1"}), required ({@code multiplicity = "1"}), or repeating groups ({@code multiplicity = "0..*"} or {@code multiplicity = "1..*"}). + * For a group of mutually exclusive arguments, making the group required means that one of the arguments in the group must appear on the command line, or a {@link MissingParameterException MissingParameterException} is thrown. + * For a group of co-occurring arguments, all arguments in the group must appear on the command line. + *

+ *

Groups can be composed for validation purposes:

+ *
    + *
  • When the parent group is mutually exclusive, only one of the subgroups may be present.
  • + *
  • When the parent group is a co-occurring group, all subgroups must be present.
  • + *
  • When the parent group is required, at least one subgroup must be present.
  • + *
+ *

+ * Below is an example of an {@code ArgGroup} defining a set of dependent options that must occur together. + * All options are required within the group, while the group itself is optional:

+ *
+     * public class DependentOptions {
+     *     @ArgGroup(exclusive = false, multiplicity = "0..1")
+     *     Dependent group;
+     *
+     *     static class Dependent {
+     *         @Option(names = "-a", required = true) int a;
+     *         @Option(names = "-b", required = true) int b;
+     *         @Option(names = "-c", required = true) int c;
+     *     }
+     * }
+ * @see ArgGroupSpec + * @since 4.0 */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) + public @interface ArgGroup { + /** The heading of this group, used when generating the usage documentation. + * When neither a {@link #heading() heading} nor a {@link #headingKey() headingKey} are specified, + * this group is used for validation only and does not change the usage help message. */ + String heading() default "__no_heading__"; + + /** ResourceBundle key for this group's usage help message section heading. + * When neither a {@link #heading() heading} nor a {@link #headingKey() headingKey} are specified, + * this group is used for validation only and does not change the usage help message. */ + String headingKey() default "__no_heading_key__"; + /** Determines whether this is a mutually exclusive group; {@code true} by default. + * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}. */ + boolean exclusive() default true; + /** Determines how often this group can be specified on the command line; {@code "0..1"} (optional) by default. + * For a group of mutually exclusive arguments, making the group required {@code multiplicity = "1"} means that + * one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown. + * For a group of co-occurring arguments, making the group required means that all arguments in the group must appear on the command line. + * Ignored if {@link #validate()} is {@code false}. */ + String multiplicity() default "0..1"; + /** Determines whether acrostics should validate the rules of this group ({@code true} by default). + * For a mutually exclusive group validation means verifying that no more than one elements of the group is specified on the command line; + * for a co-occurring group validation means verifying that all elements of the group are specified on the command line. + * Set {@link #validate() validate = false} for groups whose purpose is only to customize the usage help message. + * @see #multiplicity() + * @see #heading() */ + boolean validate() default true; + /** Determines the position in the options list in the usage help message at which this group should be shown. + * Groups with a lower number are shown before groups with a higher number. + * This attribute is only honored for groups that have a {@link #heading() heading} (or a {@link #headingKey() headingKey} with a non-{@code null} resource bundle value).*/ + int order() default -1; + } + /** + *

+ * When parsing command line arguments and initializing + * fields annotated with {@link Option @Option} or {@link Parameters @Parameters}, + * String values can be converted to any type for which a {@code ITypeConverter} is registered. + *

+ * This interface defines the contract for classes that know how to convert a String into some domain object. + * Custom converters can be registered with the {@link #registerConverter(Class, ITypeConverter)} method. + *

+ * Java 8 lambdas make it easy to register custom type converters: + *

+ *
+     * commandLine.registerConverter(java.nio.file.Path.class, s -> java.nio.file.Paths.get(s));
+     * commandLine.registerConverter(java.time.Duration.class, s -> java.time.Duration.parse(s));
+ *

+ * Built-in type converters are pre-registered for the following java 1.5 types: + *

+ *
    + *
  • all primitive types
  • + *
  • all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short
  • + *
  • any enum
  • + *
  • java.io.File
  • + *
  • java.math.BigDecimal
  • + *
  • java.math.BigInteger
  • + *
  • java.net.InetAddress
  • + *
  • java.net.URI
  • + *
  • java.net.URL
  • + *
  • java.nio.charset.Charset
  • + *
  • java.sql.Time
  • + *
  • java.util.Date
  • + *
  • java.util.UUID
  • + *
  • java.util.regex.Pattern
  • + *
  • StringBuilder
  • + *
  • CharSequence
  • + *
  • String
  • + *
+ * @param the type of the object that is the result of the conversion + */ + public interface ITypeConverter { + /** + * Converts the specified command line argument value to some domain object. + * @param value the command line argument String value + * @return the resulting domain object + * @throws Exception an exception detailing what went wrong during the conversion. + * Any exception thrown from this method will be caught and shown to the end user. + * An example error message shown to the end user could look something like this: + * {@code Invalid value for option '--some-option': cannot convert 'xxxinvalidinput' to SomeType (java.lang.IllegalArgumentException: Invalid format: must be 'x:y:z' but was 'xxxinvalidinput')} + * @throws TypeConversionException throw this exception to have more control over the error + * message that is shown to the end user when type conversion fails. + * An example message shown to the user could look like this: + * {@code Invalid value for option '--some-option': Invalid format: must be 'x:y:z' but was 'xxxinvalidinput'} + */ + K convert(String value) throws Exception; + } + + /** + * Provides version information for a command. Commands may configure a provider with the + * {@link Command#versionProvider()} annotation attribute. + * @since 2.2 */ + public interface IVersionProvider { + /** + * Returns version information for a command. + * @return version information (each string in the array is displayed on a separate line) + * @throws Exception an exception detailing what went wrong when obtaining version information + */ + String[] getVersion() throws Exception; + } + + /** + * Converter that can be used to signal to acrostics that it should use the default converter. + * This can be useful with maps: + *
+     *   class App {
+     *       @Option(names = "-D", converter = {UseDefaultConverter.class, GenericValueConverter.class})
+     *       Map<String, GenericValue<?>> values;
+     *  }
+     * 
+ * + * The {@link #convert(String)} method of this class always throws an UnsupportedOperationException. + * @since 4.7.7-SNAPSHOT + */ + public static final class UseDefaultConverter implements ITypeConverter { + /** Always throws UnsupportedOperationException. + * @throws UnsupportedOperationException always */ + public Object convert(String value) throws Exception { + throw new UnsupportedOperationException("This method should never be called."); + } + } + + private static class NoVersionProvider implements IVersionProvider { + public String[] getVersion() throws Exception { throw new UnsupportedOperationException(); } + } + + /** + * Provides a way to modify how the command model is built. + * This is useful for applications that need to modify the model dynamically depending on the runtime environment. + *

+ * Commands may configure a model transformer using the + * {@link Command#modelTransformer()} annotation attribute, or via the + * {@link CommandSpec#modelTransformer(IModelTransformer)} programmatic API. + *

+ * Model transformers are invoked only once, after the full command hierarchy is constructed. + * @since 4.6 + */ + public interface IModelTransformer { + /** + * Given an original CommandSpec, return the object that should be used + * instead. Implementors may modify the specified CommandSpec and return it, + * or create a full or partial copy of the specified CommandSpec, and return + * that, or even return a completely new CommandSpec. + *

+ * Implementors are free to add or remove options, positional parameters, + * subcommands or modify the command in any other way. + *

+ * This method is called once, after the full command hierarchy is + * constructed, and before any command line arguments are parsed. + *

+ * @return the CommandSpec to use instead of the specified one + */ + CommandSpec transform(CommandSpec commandSpec); + } + + private static class NoOpModelTransformer implements IModelTransformer { + public CommandSpec transform(CommandSpec commandSpec) { return commandSpec; } + } + + /** + * Provides default value for a command. Commands may configure a provider with the + * {@link Command#defaultValueProvider()} annotation attribute. + * @since 3.6 */ + public interface IDefaultValueProvider { + + /** Returns the default value for an option or positional parameter or {@code null}. + * The returned value is converted to the type of the option/positional parameter + * via the same type converter used when populating this option/positional + * parameter from a command line argument. + * @param argSpec the option or positional parameter, never {@code null} + * @return the default value for the option or positional parameter, or {@code null} if + * this provider has no default value for the specified option or positional parameter + * @throws Exception when there was a problem obtaining the default value + */ + String defaultValue(ArgSpec argSpec) throws Exception; + } + private static class NoDefaultProvider implements IDefaultValueProvider { + public String defaultValue(ArgSpec argSpec) { throw new UnsupportedOperationException(); } + } + + /** + * Options or positional parameters can be assigned a {@code IParameterConsumer} that implements + * custom logic to process the parameters for this option or this position. + * When an option or positional parameter with a custom {@code IParameterConsumer} is matched on the + * command line, acrostics's internal parser is temporarily suspended, and this object becomes + * responsible for consuming and processing as many command line arguments as needed. + *

This may be useful when passing through parameters to another command.

+ *

Example usage:

+ *
+     * @Command(name = "find")
+     * class Find {
+     *     @Option(names = "-exec", parameterConsumer = Find.ExecParameterConsumer.class)
+     *     List<String> list = new ArrayList<String>();
+     *
+     *     static class ExecParameterConsumer implements IParameterConsumer {
+     *         public void consumeParameters(Stack<String> args, ArgSpec argSpec, CommandSpec commandSpec) {
+     *             List<String> list = argSpec.getValue();
+     *             while (!args.isEmpty()) {
+     *                 String arg = args.pop();
+     *                 list.add(arg);
+     *
+     *                 // `find -exec` semantics: stop processing after a ';' or '+' argument
+     *                 if (";".equals(arg) || "+".equals(arg)) {
+     *                     break;
+     *                 }
+     *             }
+     *         }
+     *     }
+     * }
+ *

If this interface does not meet your requirements, you may have a look at the more powerful + * and flexible {@link IParameterPreprocessor} interface introduced with acrostics 4.6.

+ * @see Option#parameterConsumer() + * @see Parameters#parameterConsumer() + * @since 4.0 */ + public interface IParameterConsumer { + /** + * Consumes as many of the specified command line arguments as needed by popping them off + * the specified Stack. Implementors are free to ignore the {@linkplain ArgSpec#arity() arity} + * of the option or positional parameter, they are free to consume arguments that would + * normally be matched as other options of the command, and they are free to consume + * arguments that would normally be matched as an end-of-options delimiter. + *

Implementors are responsible for saving the consumed values; + * if the user object of the option or positional parameter is a Collection + * or a Map, a common approach would be to obtain the current instance via the + * {@link ArgSpec#getValue()}, and add to this instance. If the user object is an + * array, the implementation would need to create a new array that contains the + * old values as well as the newly consumed values, and store this array in the + * user object via the {@link ArgSpec#setValue(Object)}. + *

+ * If the user input is invalid, implementations should throw a {@link ParameterException} + * with a message to display to the user. + *

+ * When this method returns, the acrostics parser will process the remaining arguments on the Stack. + *

+ * @param args the command line arguments + * @param argSpec the option or positional parameter for which to consume command line arguments + * @param commandSpec the command that the option or positional parameter belongs to + * @throws ParameterException if the user input is invalid + */ + void consumeParameters(Stack args, ArgSpec argSpec, CommandSpec commandSpec); + } + private static class NullParameterConsumer implements IParameterConsumer { + public void consumeParameters(Stack args, ArgSpec argSpec, CommandSpec commandSpec) { throw new UnsupportedOperationException(); } + } + /** + * Options, positional parameters and commands can be assigned a {@code IParameterPreprocessor} that + * implements custom logic to preprocess the parameters for this option, position or command. + * When an option, positional parameter or command with a custom {@code IParameterPreprocessor} is matched + * on the command line, acrostics's internal parser is temporarily suspended, and this custom logic is invoked. + *

+ * This custom logic may completely replace acrostics's internal parsing for this option, positional parameter + * or command, or it may do some preprocessing before acrostics's internal parsing is resumed for this option, + * positional parameter or command. + *

+ * The "preprocessing" can include modifying the stack of command line parameters, or modifying the model. + *

+ *

This may be useful when disambiguating input for commands that have both a positional parameter and an + * option with an optional parameter.

+ *

Example usage:

+ *
+     * @Command(name = "edit")
+     * class Edit {
+     *     @Parameters(index = "0", description = "The file to edit.")
+     *     File file;
+     *
+     *     enum Editor { defaultEditor, eclipse, idea, netbeans }
+     *
+     *     @Option(names = "--open", arity = "0..1", preprocessor = Edit.MyPreprocessor.class,
+     *         description = {
+     *             "Optionally specify the editor to use; if omitted the default editor is used. ",
+     *             "Example: edit --open=idea FILE opens IntelliJ IDEA (notice the '=' separator)",
+     *             "         edit --open FILE opens the specified file in the default editor"
+     *         })
+     *     Editor editor = Editor.defaultEditor;
+     *
+     *     static class MyPreprocessor implements IParameterPreprocessor {
+     *         public boolean preprocess(Stack<String> args, CommandSpec commandSpec, ArgSpec argSpec, Map<String, Object> info) {
+     *             // we need to decide whether the next arg is the file to edit or the name of the editor to use...
+     *             if (" ".equals(info.get("separator"))) { // parameter was not attached to option
+     *                 args.push(Editor.defaultEditor.name()); // act as if the user specified --open=defaultEditor
+     *             }
+     *             return false; // acrostics's internal parsing is resumed for this option
+     *         }
+     *     }
+     * }
+ * @see Option#preprocessor() + * @see Parameters#preprocessor() + * @since 4.6 */ + public interface IParameterPreprocessor { + /** + * Called when either the command, option or positional parameter that has this preprocessor configured was + * recognized by the acrostics parser. + *

Implementors are free to modify one or more of the specified command line arguments before they are + * processed by the acrostics parser (or by the option's {@link IParameterConsumer parameter consumer}, if one is specified). + *

+ * Implementors may optionally consume one or more of the specified command line arguments: + * a return value of {@code true} signals that the preprocessor consumed the parameter: + * acrostics should skip further processing of this option or positional parameter, + * and the preprocessor implementation takes responsibility for assigning the + * option or positional parameter a value. A return value of {@code false} means that acrostics should + * process the stack as usual for this option or positional parameter, and acrostics is responsible for + * assigning this option or positional parameter a value. + *

+ * For a command, returning {@code true} signals that the preprocessor takes responsibility for parsing all + * options and positional parameters for this command, and takes responsibility for validating constraints like + * whether all required options and positional parameters were specified. + * A return value of {@code false} means that acrostics should + * process the stack as usual for this command, and acrostics is responsible for validation. + * Command preprocessors can signal back to the acrostics parser when they detect that the user requested version + * information or usage help by putting a value of {@code true} in the specified + * {@code info} map for keys {@code versionHelpRequested} or {@code usageHelpRequested}, respectively. + *

+ * If the user input is invalid, implementations should throw a {@link ParameterException} + * with a message to display to the user. + *

+ * @param args the remaining command line arguments that follow the matched argument + * (the matched argument is not on the stack anymore) + * @param commandSpec the command or subcommand that was matched (if the specified {@code argSpec} is + * {@code null}), or the command that the matched option or positional parameter belongs to + * @param argSpec the option or positional parameter for which to pre-process command line arguments + * (may be {@code null} when this method is called for a subcommand that was matched) + * @param info a map containing additional information on the current parser state, + * including whether the option parameter was attached to the option name with + * a `=` separator, whether quotes have already been stripped off the option, etc. + * Implementations may modify this map to communicate back to the acrostics parser. + * Supported values: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Supported values in the info Map
keyvalid valuestype
separator'' (empty string): attached without separator, ' ' (space): not attached, (any other string): option name was attached to option param with specified separatorjava.lang.String
negated{@code true}: the option or positional parameter is a {@linkplain Option#negatable() negated} option/parameter, {@code false}: the option or positional parameter is not a negated option/parameterjava.lang.Boolean
unquoted{@code true}: quotes surrounding the value have already been stripped off, {@code false}: quotes surrounding the value have not yet been stripped offjava.lang.Boolean
versionHelpRequested{@code true}: version help was requested, {@code false}: version help was not requestedjava.lang.Boolean
usageHelpRequested{@code true}: usage help was requested, {@code false}: usage help was not requestedjava.lang.Boolean
+ * @return true if the preprocessor consumed the parameter + * and acrostics should skip further processing of the stack for this option or positional parameter; + * false if acrostics should continue processing the stack for this option or positional parameter + * @throws ParameterException if the user input is invalid + */ + boolean preprocess(Stack args, CommandSpec commandSpec, ArgSpec argSpec, Map info); + } + private static class NoOpParameterPreprocessor implements IParameterPreprocessor { + public boolean preprocess(Stack args, CommandSpec commandSpec, ArgSpec argSpec, Map info) { return false; } + public boolean equals(Object obj) { return obj instanceof NoOpParameterPreprocessor; } + public int hashCode() { return NoOpParameterPreprocessor.class.hashCode() + 7; } + } + + /** Determines the option name transformation of {@linkplain Option#negatable() negatable} boolean options. + * Making an option negatable has two aspects: + *
    + *
  • the negative form recognized by the parser while parsing the command line
  • + *
  • the documentation string showing both the positive and the negative form in the usage help message
  • + *

+ * Additionally, this transformer controls which names of a negatable option are actually negatable: + * for example, by default short options like {@code -v} do not have a negative form, even if the same option's + * long form, {@code --verbose}, may have a negative form, {@code --no-verbose}. + *

+ * @see RegexTransformer + * @since 4.0 + */ + public interface INegatableOptionTransformer { + /** Returns the negative form of the specified option name for the parser to recognize when parsing command line arguments. + * @param optionName the option name to create a negative form for, for example {@code --force} + * @param cmd the command that the option is part of + * @return the negative form of the specified option name, for example {@code --no-force} + */ + String makeNegative(String optionName, CommandSpec cmd); + /** Returns the documentation string to show in the synopsis and usage help message for the specified option. + * The returned value should be concise and clearly suggest that both the positive and the negative form are valid option names + * @param optionName the option name to create a documentation string for, for example {@code --force}, or {@code -XX:+