From 73fb412cfc1e6a61bcbbddb510dbf34f90fb9840 Mon Sep 17 00:00:00 2001 From: Martchus Date: Wed, 14 Mar 2018 18:44:33 +0100 Subject: [PATCH] Simplify creation of CLI arguments --- application/main.cpp | 146 +++++++++++++------------------------------ cli/mainfeatures.h | 56 ++++++++--------- 2 files changed, 70 insertions(+), 132 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index b8478de..aa21c5f 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -28,85 +28,68 @@ namespace Cli { SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg) : filesArg(filesArg) , verboseArg(verboseArg) - , docTitleArg("doc-title", 'd', "specifies the document title (has no affect if not supported by the container)") + , docTitleArg("doc-title", 'd', "specifies the document title (has no affect if not supported by the container)", + { "title of first segment", "title of second segment" }) , removeOtherFieldsArg( "remove-other-fields", '\0', "removes ALL fields where no value has been provided for (to remove a specific field use eg. \"album=\")") - , treatUnknownFilesAsMp3FilesArg("treat-unknown-as-mp3", '\0', "if present unknown files will be treatet as MP3 files") + , treatUnknownFilesAsMp3FilesArg("treat-unknown-as-mp3", '\0', "if present unknown files will be treated as MP3 files") , id3v1UsageArg("id3v1-usage", '\0', "specifies the ID3v1 usage (only used when already present by default); only relevant when dealing with MP3 files (or files treated as " - "such)") + "such)", + { "always/keepexisting/never" }) , id3v2UsageArg("id3v2-usage", '\0', - "specifies the ID3v2 usage (always used by default); only relevant when dealing with MP3 files (or files treated as such)") + "specifies the ID3v2 usage (always used by default); only relevant when dealing with MP3 files (or files treated as such)", + { "always/keepexisting/never" }) , mergeMultipleSuccessiveTagsArg("merge-successive-tags", '\0', "if present multiple successive ID3v2 tags will be merged") - , id3v2VersionArg("id3v2-version", '\0', "forces a specific ID3v2 version to be used; only relevant when ID3v2 is used") + , id3v2VersionArg("id3v2-version", '\0', "forces a specific ID3v2 version to be used; only relevant when ID3v2 is used", { "1/2/3/4" }) , id3InitOnCreateArg("id3-init-on-create", '\0', "indicates whether to initialize newly created ID3 tags (according to specified usage) with the values of the already present ID3 tags") , id3TransferOnRemovalArg("id3-transfer-on-removal", '\0', "indicates whether values of removed ID3 tags (according to specified usage) should be transfered to remaining ID3 tags (no values will be " "overwritten)") - , encodingArg("encoding", '\0', "specifies the preferred encoding") + , encodingArg("encoding", '\0', "specifies the preferred encoding", { "latin1/utf8/utf16le/utf16be" }) , removeTargetArg("remove-target", '\0', "removes all tags with the specified target") - , addAttachmentArg("add-attachment", '\0', "adds a new attachment") - , updateAttachmentArg("update-attachment", '\0', "updates an existing attachment") + , addAttachmentArg("add-attachment", '\0', "adds a new attachment", { "path=some/file", "name=Some name", "desc=Some desc", "mime=mime/type" }) + , updateAttachmentArg( + "update-attachment", '\0', "updates an existing attachment", { "path=some/file", "name=Some name", "desc=Some desc", "mime=mime/type" }) , removeAttachmentArg("remove-attachment", '\0', "removes an existing attachment") , removeExistingAttachmentsArg( "remove-existing-attachments", 'r', "removes ALL existing attachments (to remove a specific attachment use --remove-attachment)") - , minPaddingArg( - "min-padding", '\0', "specifies the minimum padding before the media data (enforces rewriting the file is the padding would be less)") - , maxPaddingArg( - "max-padding", '\0', "specifies the maximum padding before the media data (enforces rewriting the file is the padding would be more)") - , prefPaddingArg("preferred-padding", '\0', "specifies the preferred padding before the media data (used when the file is rewritten)") - , tagPosValueArg("value", '\0', "specifies the position, either front, back or current") + , minPaddingArg("min-padding", '\0', + "specifies the minimum padding before the media data (enforces rewriting the file is the padding would be less)", + { "min. padding in byte" }) + , maxPaddingArg("max-padding", '\0', + "specifies the maximum padding before the media data (enforces rewriting the file is the padding would be more)", + { "max. padding in byte" }) + , prefPaddingArg("preferred-padding", '\0', "specifies the preferred padding before the media data (used when the file is rewritten)", + { "preferred padding in byte" }) + , tagPosValueArg("value", '\0', "specifies the position, either front, back or current", { "front/back/current" }) , forceTagPosArg("force", '\0', "forces the specified position even if the file needs to be rewritten") , tagPosArg("tag-pos", '\0', "specifies the preferred tag position") - , indexPosValueArg("value", '\0', "specifies the position, either front, back or current") + , indexPosValueArg("value", '\0', "specifies the position, either front, back or current", { "front/back/current" }) , forceIndexPosArg("force", '\0', "forces the specified position even if the file needs to be rewritten") , indexPosArg("index-pos", '\0', "specifies the preferred index position") , forceRewriteArg( "force-rewrite", '\0', "forces the file to rewritten from the scratch which ensures a backup is created and the preferred padding is used") - , valuesArg("values", 'n', "specifies the values to be set") - , outputFilesArg("output-files", 'o', "specifies the output files; if present, the files specified with --files will not be modified") + , valuesArg("values", 'n', "specifies the values to be set", { "title=foo", "album=bar", "cover=/path/to/file" }) + , outputFilesArg("output-files", 'o', "specifies the output files; if present, the files specified with --files will not be modified", + { "path 1", "path 2" }) , backupDirArg("temp-dir", '\0', "specifies the directory for temporary/backup files", { "path" }) , layoutOnlyArg("layout-only", 'l', "confirms layout-only changes") , setTagInfoArg("set", 's', "sets the specified tag information and attachments") { - docTitleArg.setCombinable(true); docTitleArg.setRequiredValueCount(Argument::varValueCount); - docTitleArg.setValueNames({ "title of first segment", "title of second segment" }); - removeOtherFieldsArg.setCombinable(true); - treatUnknownFilesAsMp3FilesArg.setCombinable(true); - id3v1UsageArg.setRequiredValueCount(1); - id3v1UsageArg.setValueNames({ "always/keepexisting/never" }); id3v1UsageArg.setPreDefinedCompletionValues("always keepexisting never"); - id3v1UsageArg.setCombinable(true); - id3v2UsageArg.setRequiredValueCount(1); - id3v2UsageArg.setValueNames({ "always/keepexisting/never" }); id3v2UsageArg.setPreDefinedCompletionValues("always keepexisting never"); - id3v2UsageArg.setCombinable(true); - mergeMultipleSuccessiveTagsArg.setCombinable(true); - id3v2VersionArg.setRequiredValueCount(1); - id3v2VersionArg.setValueNames({ "1/2/3/4" }); - id3v2VersionArg.setCombinable(true); id3v2VersionArg.setPreDefinedCompletionValues("1 2 3 4"); - id3InitOnCreateArg.setCombinable(true); - id3TransferOnRemovalArg.setCombinable(true); - encodingArg.setRequiredValueCount(1); - encodingArg.setValueNames({ "latin1/utf8/utf16le/utf16be" }); encodingArg.setPreDefinedCompletionValues("latin1 utf8 utf16le utf16be"); - encodingArg.setCombinable(true); removeTargetArg.setRequiredValueCount(Argument::varValueCount); - removeTargetArg.setValueNames({}); - removeTargetArg.setCombinable(true); removeTargetArg.setConstraints(0, Argument::varValueCount); addAttachmentArg.setRequiredValueCount(Argument::varValueCount); - addAttachmentArg.setValueNames({ "path=some/file", "name=Some name", "desc=Some desc", "mime=mime/type" }); - addAttachmentArg.setCombinable(true); addAttachmentArg.setConstraints(0, Argument::varValueCount); addAttachmentArg.setValueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::AppendEquationSign); addAttachmentArg.setPreDefinedCompletionValues("name id path desc mime"); updateAttachmentArg.setRequiredValueCount(Argument::varValueCount); - updateAttachmentArg.setValueNames({ "path=some/file", "name=Some name", "desc=Some desc", "mime=mime/type" }); - updateAttachmentArg.setCombinable(true); updateAttachmentArg.setConstraints(0, Argument::varValueCount); updateAttachmentArg.setValueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::AppendEquationSign); updateAttachmentArg.setPreDefinedCompletionValues("name id path desc mime"); @@ -116,43 +99,20 @@ SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg) removeAttachmentArg.setConstraints(0, Argument::varValueCount); removeAttachmentArg.setPreDefinedCompletionValues("name id"); removeAttachmentArg.setValueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::AppendEquationSign); - removeExistingAttachmentsArg.setCombinable(true); - minPaddingArg.setRequiredValueCount(1); - minPaddingArg.setValueNames({ "min padding in byte" }); - minPaddingArg.setCombinable(true); - maxPaddingArg.setRequiredValueCount(1); - maxPaddingArg.setValueNames({ "min padding in byte" }); - maxPaddingArg.setCombinable(true); - prefPaddingArg.setRequiredValueCount(1); - prefPaddingArg.setValueNames({ "preferred padding in byte" }); - prefPaddingArg.setCombinable(true); - tagPosValueArg.setRequiredValueCount(1); - tagPosValueArg.setValueNames({ "front/back/current" }); tagPosValueArg.setPreDefinedCompletionValues("front back current"); tagPosValueArg.setImplicit(true); tagPosValueArg.setRequired(true); - forceTagPosArg.setCombinable(true); - tagPosArg.setCombinable(true); tagPosArg.setSubArguments({ &tagPosValueArg, &forceTagPosArg }); - forceIndexPosArg.setCombinable(true); - indexPosValueArg.setRequiredValueCount(1); - indexPosValueArg.setValueNames({ "front/back/current" }); indexPosValueArg.setPreDefinedCompletionValues("front back current"); indexPosValueArg.setImplicit(true); indexPosValueArg.setRequired(true); - indexPosArg.setCombinable(true); indexPosArg.setExample(PROJECT_NAME " set comment=\"with faststart\" --index-pos front --force --layout-only -f /some/dir/*.m4a"); indexPosArg.setSubArguments({ &indexPosValueArg, &forceIndexPosArg }); - forceRewriteArg.setCombinable(true); - valuesArg.setValueNames({ "title=foo", "album=bar", "cover=/path/to/file" }); valuesArg.setRequiredValueCount(Argument::varValueCount); valuesArg.setImplicit(true); valuesArg.setPreDefinedCompletionValues(Cli::fieldNamesForSet); valuesArg.setValueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::AppendEquationSign); - outputFilesArg.setValueNames({ "path 1", "path 2" }); outputFilesArg.setRequiredValueCount(Argument::varValueCount); - outputFilesArg.setCombinable(true); - setTagInfoArg.setDenotesOperation(true); setTagInfoArg.setCallback(std::bind(Cli::setTagInfo, std::cref(*this))); setTagInfoArg.setExample(PROJECT_NAME " set title=\"Title of \"{1st,2nd,3rd}\" file\" title=\"Title of \"{4..16}\"th file\" album=\"The Album\" -f /some/dir/*.m4a\n" PROJECT_NAME @@ -181,78 +141,56 @@ int main(int argc, char *argv[]) ConfigValueArgument timeSpanFormatArg("time-span-format", '\0', "specifies the output format for time spans", { "measures/colons/seconds" }); timeSpanFormatArg.setPreDefinedCompletionValues("measures colons seconds"); // verbose option - Argument verboseArg("verbose", 'v', "be verbose"); - verboseArg.setCombinable(true); + ConfigValueArgument verboseArg("verbose", 'v', "be verbose"); // input/output file/files - Argument fileArg("file", 'f', "specifies the path of the file to be opened"); - fileArg.setValueNames({ "path" }); - fileArg.setRequiredValueCount(1); - fileArg.setCombinable(true); - Argument defaultFileArg(fileArg); + ConfigValueArgument fileArg("file", 'f', "specifies the path of the file to be opened", { "path" }); + ConfigValueArgument defaultFileArg(fileArg); defaultFileArg.setImplicit(true); fileArg.setRequired(true); - Argument filesArg("files", 'f', "specifies the path of the file(s) to be opened"); - filesArg.setValueNames({ "path 1", "path 2" }); + ConfigValueArgument filesArg("files", 'f', "specifies the path of the file(s) to be opened", { "path 1", "path 2" }); filesArg.setRequiredValueCount(Argument::varValueCount); - filesArg.setCombinable(true); - Argument outputFileArg("output-file", 'o', "specifies the path of the output file"); - outputFileArg.setValueNames({ "path" }); - outputFileArg.setRequiredValueCount(1); - outputFileArg.setCombinable(true); + ConfigValueArgument outputFileArg("output-file", 'o', "specifies the path of the output file", { "path" }); // print field names - Argument printFieldNamesArg("print-field-names", '\0', "lists available field names, track attribute names and modifier"); + OperationArgument printFieldNamesArg("print-field-names", '\0', "lists available field names, track attribute names and modifier"); printFieldNamesArg.setCallback(Cli::printFieldNames); // display general file info - Argument displayFileInfoArg("info", 'i', "displays general file information"); - displayFileInfoArg.setDenotesOperation(true); - displayFileInfoArg.setExample(PROJECT_NAME " info -f /some/dir/*.m4a"); + OperationArgument displayFileInfoArg("info", 'i', "displays general file information", PROJECT_NAME " info -f /some/dir/*.m4a"); displayFileInfoArg.setCallback(std::bind(Cli::displayFileInfo, _1, std::cref(filesArg), std::cref(verboseArg))); displayFileInfoArg.setSubArguments({ &filesArg, &verboseArg }); // display tag info - Argument fieldsArg("fields", 'n', "specifies the field names to be displayed"); - fieldsArg.setValueNames({ "title", "album", "artist", "trackpos" }); + ConfigValueArgument fieldsArg("fields", 'n', "specifies the field names to be displayed", { "title", "album", "artist", "trackpos" }); fieldsArg.setRequiredValueCount(Argument::varValueCount); fieldsArg.setPreDefinedCompletionValues(Cli::fieldNames); fieldsArg.setImplicit(true); - Argument displayTagInfoArg("get", 'g', "displays the values of all specified tag fields (displays all fields if none specified)"); - displayTagInfoArg.setDenotesOperation(true); + OperationArgument displayTagInfoArg("get", 'g', "displays the values of all specified tag fields (displays all fields if none specified)", + PROJECT_NAME " get title album artist -f /some/dir/*.m4a"); displayTagInfoArg.setCallback(std::bind(Cli::displayTagInfo, std::cref(fieldsArg), std::cref(filesArg), std::cref(verboseArg))); - displayTagInfoArg.setExample(PROJECT_NAME " get title album artist -f /some/dir/*.m4a"); displayTagInfoArg.setSubArguments({ &fieldsArg, &filesArg, &verboseArg }); // set tag info Cli::SetTagInfoArgs setTagInfoArgs(filesArg, verboseArg); // extract cover - Argument fieldArg("field", 'n', "specifies the field to be extracted"); - fieldArg.setValueNames({ "field name" }); - fieldArg.setRequiredValueCount(1); + ConfigValueArgument fieldArg("field", 'n', "specifies the field to be extracted", { "field name" }); fieldArg.setImplicit(true); - Argument attachmentArg("attachment", 'a', "specifies the attachment to be extracted"); - attachmentArg.setValueNames({ "id=..." }); - attachmentArg.setRequiredValueCount(1); - Argument extractFieldArg("extract", 'e', + ConfigValueArgument attachmentArg("attachment", 'a', "specifies the attachment to be extracted", { "id=..." }); + OperationArgument extractFieldArg("extract", 'e', "saves the value of the specified field (eg. cover or other binary field) or attachment to the specified file or writes it to stdout if no " "output file has been specified"); extractFieldArg.setSubArguments({ &fieldArg, &attachmentArg, &fileArg, &outputFileArg, &verboseArg }); - extractFieldArg.setDenotesOperation(true); extractFieldArg.setCallback(std::bind( Cli::extractField, std::cref(fieldArg), std::cref(attachmentArg), std::cref(fileArg), std::cref(outputFileArg), std::cref(verboseArg))); // export to JSON ConfigValueArgument prettyArg("pretty", '\0', "prints with indentation and spacing"); - Argument exportArg("export", 'j', "exports the tag information for the specified files to JSON"); + OperationArgument exportArg("export", 'j', "exports the tag information for the specified files to JSON"); exportArg.setSubArguments({ &filesArg, &prettyArg }); - exportArg.setDenotesOperation(true); exportArg.setCallback(std::bind(Cli::exportToJson, _1, std::cref(filesArg), std::cref(prettyArg))); // file info - Argument validateArg( + ConfigValueArgument validateArg( "validate", 'c', "validates the file integrity as accurately as possible; the structure of the file will be parsed completely"); - validateArg.setCombinable(true); - Argument genInfoArg("html-info", '\0', "generates technical information about the specified file as HTML document"); - genInfoArg.setDenotesOperation(true); + OperationArgument genInfoArg("html-info", '\0', "generates technical information about the specified file as HTML document"); genInfoArg.setSubArguments({ &fileArg, &validateArg, &outputFileArg }); genInfoArg.setCallback(std::bind(Cli::generateFileInfo, _1, std::cref(fileArg), std::cref(outputFileArg), std::cref(validateArg))); // renaming utility - Argument renamingUtilityArg("renaming-utility", '\0', "launches the renaming utility instead of the main GUI"); - renamingUtilityArg.setCombinable(true); + ConfigValueArgument renamingUtilityArg("renaming-utility", '\0', "launches the renaming utility instead of the main GUI"); // set arguments to parser qtConfigArgs.qtWidgetsGuiArg().setAbbreviation('\0'); qtConfigArgs.qtWidgetsGuiArg().addSubArgument(&defaultFileArg); diff --git a/cli/mainfeatures.h b/cli/mainfeatures.h index aea9391..7f455de 100644 --- a/cli/mainfeatures.h +++ b/cli/mainfeatures.h @@ -13,36 +13,36 @@ struct SetTagInfoArgs { SetTagInfoArgs(ApplicationUtilities::Argument &filesArg, ApplicationUtilities::Argument &verboseArg); ApplicationUtilities::Argument &filesArg; ApplicationUtilities::Argument &verboseArg; - ApplicationUtilities::Argument docTitleArg; - ApplicationUtilities::Argument removeOtherFieldsArg; - ApplicationUtilities::Argument treatUnknownFilesAsMp3FilesArg; - ApplicationUtilities::Argument id3v1UsageArg; - ApplicationUtilities::Argument id3v2UsageArg; - ApplicationUtilities::Argument mergeMultipleSuccessiveTagsArg; - ApplicationUtilities::Argument id3v2VersionArg; - ApplicationUtilities::Argument id3InitOnCreateArg; - ApplicationUtilities::Argument id3TransferOnRemovalArg; - ApplicationUtilities::Argument encodingArg; - ApplicationUtilities::Argument removeTargetArg; - ApplicationUtilities::Argument addAttachmentArg; - ApplicationUtilities::Argument updateAttachmentArg; - ApplicationUtilities::Argument removeAttachmentArg; - ApplicationUtilities::Argument removeExistingAttachmentsArg; - ApplicationUtilities::Argument minPaddingArg; - ApplicationUtilities::Argument maxPaddingArg; - ApplicationUtilities::Argument prefPaddingArg; - ApplicationUtilities::Argument tagPosValueArg; - ApplicationUtilities::Argument forceTagPosArg; - ApplicationUtilities::Argument tagPosArg; - ApplicationUtilities::Argument indexPosValueArg; - ApplicationUtilities::Argument forceIndexPosArg; - ApplicationUtilities::Argument indexPosArg; - ApplicationUtilities::Argument forceRewriteArg; - ApplicationUtilities::Argument valuesArg; - ApplicationUtilities::Argument outputFilesArg; + ApplicationUtilities::ConfigValueArgument docTitleArg; + ApplicationUtilities::ConfigValueArgument removeOtherFieldsArg; + ApplicationUtilities::ConfigValueArgument treatUnknownFilesAsMp3FilesArg; + ApplicationUtilities::ConfigValueArgument id3v1UsageArg; + ApplicationUtilities::ConfigValueArgument id3v2UsageArg; + ApplicationUtilities::ConfigValueArgument mergeMultipleSuccessiveTagsArg; + ApplicationUtilities::ConfigValueArgument id3v2VersionArg; + ApplicationUtilities::ConfigValueArgument id3InitOnCreateArg; + ApplicationUtilities::ConfigValueArgument id3TransferOnRemovalArg; + ApplicationUtilities::ConfigValueArgument encodingArg; + ApplicationUtilities::ConfigValueArgument removeTargetArg; + ApplicationUtilities::ConfigValueArgument addAttachmentArg; + ApplicationUtilities::ConfigValueArgument updateAttachmentArg; + ApplicationUtilities::ConfigValueArgument removeAttachmentArg; + ApplicationUtilities::ConfigValueArgument removeExistingAttachmentsArg; + ApplicationUtilities::ConfigValueArgument minPaddingArg; + ApplicationUtilities::ConfigValueArgument maxPaddingArg; + ApplicationUtilities::ConfigValueArgument prefPaddingArg; + ApplicationUtilities::ConfigValueArgument tagPosValueArg; + ApplicationUtilities::ConfigValueArgument forceTagPosArg; + ApplicationUtilities::ConfigValueArgument tagPosArg; + ApplicationUtilities::ConfigValueArgument indexPosValueArg; + ApplicationUtilities::ConfigValueArgument forceIndexPosArg; + ApplicationUtilities::ConfigValueArgument indexPosArg; + ApplicationUtilities::ConfigValueArgument forceRewriteArg; + ApplicationUtilities::ConfigValueArgument valuesArg; + ApplicationUtilities::ConfigValueArgument outputFilesArg; ApplicationUtilities::ConfigValueArgument backupDirArg; ApplicationUtilities::ConfigValueArgument layoutOnlyArg; - ApplicationUtilities::Argument setTagInfoArg; + ApplicationUtilities::OperationArgument setTagInfoArg; }; extern const char *const fieldNames;