diff --git a/README.md b/README.md
index 521a5dc3..ea417b9b 100644
--- a/README.md
+++ b/README.md
@@ -101,6 +101,7 @@ It's how the argc parser identifies configuration.
| Tag | Description |
| :---------------------------------------------- | ------------------------------------ |
+| [`@describe`](./docs/specification.md#describe) | Set the description for the command. |
| [`@cmd`](./docs/specification.md#cmd) | Define a subcommand. |
| [`@alias`](./docs/specification.md#alias) | Set aliases for the subcommand. |
| [`@arg`](./docs/specification.md#arg) | Define a positional argument. |
@@ -108,9 +109,6 @@ It's how the argc parser identifies configuration.
| [`@flag`](./docs/specification.md#flag) | Define a flag argument. |
| [`@env`](./docs/specification.md#env) | Define an environment variable. |
| [`@meta`](./docs/specification.md#meta) | Add a metadata. |
-| [`@describe`](./docs/specification.md#describe) | Set the description for the command. |
-| [`@version`](./docs/specification.md#version) | Set the version for the command. |
-| [`@author`](./docs/specification.md#author) | Set the author for the command. |
See [specification](https://github.com/sigoden/argc/blob/main/docs/specification.md) for the grammar and usage of all the comment tags.
diff --git a/docs/specification.md b/docs/specification.md
index 4b336b04..34ad8f9b 100644
--- a/docs/specification.md
+++ b/docs/specification.md
@@ -1,5 +1,24 @@
# Specification
+### `@describe`
+
+Set the description for the command.
+
+> **Syntax**\
+> `@describe` string
+
+```sh
+# @describe A demo CLI
+```
+
+```sh
+# @describe Multi-line auto-wrapped help text
+#
+# Extra lines after the @cmd or @describe, which don't start with an @, are
+# treated as the long description. A line which is not a comment ends
+# the block.
+```
+
## `@cmd`
Define a subcommand.
@@ -150,49 +169,49 @@ Add a metadata.
| syntax | scope | description |
| :--------------------------- | ------ | :------------------------------------------------------------------- |
-| `@meta dotenv []` | root | Load a `.env` file from a custom path, if persent. |
+| `@meta version ` | any | Set the version for the command. |
+| `@meta author ` | any | Set the author for the command. |
+| `@meta dotenv []` | root | Load a dotenv file from a custom path, if persent. |
+| `@meta symbol ` | any | Define a symbolic parameter, e.g. `+toolchain`, `@argument-file`. |
+| `@meta man-section <1-8>` | root | Override the section for the man page, defaulting to 1. |
| `@meta default-subcommand` | subcmd | Set the current subcommand as the default. |
| `@meta inherit-flag-options` | root | Subcommands will inherit the flags/options from their parent. |
-| `@meta no-inherit-env` | root | Subcommands don't inherit the env vars from their parent. |
-| `@meta symbol ` | anycmd | Define a symbolic parameter, e.g. `+toolchain`, `@argument-file`. |
+| `@meta no-inherit-env` | root | Subcommands will not inherit the env vars from their parent. |
| `@meta combine-shorts` | root | Short flags/options can be combined, e.g. `prog -xf => prog -x -f `. |
-| `@meta man-section <1-8>` | root | Override the default section the man page. |
-
-### `@describe`
-
-Set the description for the command.
-
-> **Syntax**\
-> `@describe` string
```sh
-# @describe A demo cli
+# @meta version 1.0.0
+# @meta author nobody
+# @meta dotenv .env.local # Load .env.local
+# @meta dotenv # Load .env
+# @meta symbol +toolchain[`_choice_fn`]
+# @meta man-section 8 # Generate to man section 8
```
-## `@version`
+## Deprecated Tags
-Set the version for the command.
+Deprecated tags can still be used, but are not recommended and may be completely abandoned in subsequent versions.
-> **Syntax**\
-> `@version` string
+### `@version`
-```sh
-# @version 2.17.1
+Set the version for the command.
+
+```diff
+-- # @version 2.17.1
+++ # @meta version 2.17.1
```
-## `@author`
+### `@author`
Set the author for the command.
-```sh
-# @author alice
+```diff
+-- # @author nobody
+++ # @meta author nobody
```
-> **Syntax**\
-> `@author` string
-
-## Component
+## Internal components
### short
diff --git a/src/command/mod.rs b/src/command/mod.rs
index aad54ce4..9af6eb87 100644
--- a/src/command/mod.rs
+++ b/src/command/mod.rs
@@ -12,9 +12,9 @@ use crate::param::{
};
use crate::parser::{parse, parse_symbol, Event, EventData, EventScope, Position};
use crate::utils::{
- AFTER_HOOK, BEFORE_HOOK, INTERNAL_SYMBOL, MAIN_NAME, META_COMBINE_SHORTS,
+ AFTER_HOOK, BEFORE_HOOK, INTERNAL_SYMBOL, MAIN_NAME, META_AUTHOR, META_COMBINE_SHORTS,
META_DEFAULT_SUBCOMMAND, META_DOTENV, META_INHERIT_FLAG_OPTIONS, META_NO_INHERIT_ENV,
- META_SYMBOL, ROOT_NAME,
+ META_SYMBOL, META_VERSION, ROOT_NAME,
};
use crate::Result;
@@ -150,12 +150,29 @@ impl Command {
}
EventData::Meta(key, value) => {
let cmd = Self::get_cmd(&mut root_cmd, "@meta", position)?;
- if key == META_SYMBOL {
- let (ch, name, choice_fn) = parse_symbol(&value).ok_or_else(|| {
- anyhow!("@meta(line {}) invalid symbol value", position)
- })?;
- cmd.symbols
- .insert(ch, (name.to_string(), choice_fn.map(|v| v.to_string())));
+ match key.as_str() {
+ META_SYMBOL => {
+ let (ch, name, choice_fn) = parse_symbol(&value).ok_or_else(|| {
+ anyhow!("@meta(line {}) invalid symbol value", position)
+ })?;
+ cmd.symbols
+ .insert(ch, (name.to_string(), choice_fn.map(|v| v.to_string())));
+ }
+ META_VERSION => {
+ if value.is_empty() {
+ bail!("@meta(line {}) invalid version value", position)
+ } else {
+ cmd.version = Some(value.clone());
+ }
+ }
+ META_AUTHOR => {
+ if value.is_empty() {
+ bail!("@meta(line {}) invalid version value", position)
+ } else {
+ cmd.author = Some(value.clone());
+ }
+ }
+ _ => {}
}
cmd.metadata.push((key, value, position));
}
diff --git a/src/utils.rs b/src/utils.rs
index 627e12eb..34612ad1 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -14,6 +14,8 @@ pub const AFTER_HOOK: &str = "_argc_after";
pub const ROOT_NAME: &str = "prog";
pub const MAIN_NAME: &str = "main";
+pub(crate) const META_VERSION: &str = "version";
+pub(crate) const META_AUTHOR: &str = "author";
pub(crate) const META_DOTENV: &str = "dotenv";
pub(crate) const META_DEFAULT_SUBCOMMAND: &str = "default-subcommand";
pub(crate) const META_INHERIT_FLAG_OPTIONS: &str = "inherit-flag-options";
diff --git a/tests/snapshots/integration__validate__help_version_legacy.snap b/tests/snapshots/integration__validate__help_version_legacy.snap
new file mode 100644
index 00000000..ce642f3f
--- /dev/null
+++ b/tests/snapshots/integration__validate__help_version_legacy.snap
@@ -0,0 +1,123 @@
+---
+source: tests/validate.rs
+expression: data
+---
+************ RUN ************
+prog help
+
+# OUTPUT
+command cat >&2 <<-'EOF'
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+EOF
+exit 0
+
+# RUN_OUTPUT
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+************ RUN ************
+prog --help
+
+# OUTPUT
+command cat >&2 <<-'EOF'
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+EOF
+exit 0
+
+# RUN_OUTPUT
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+************ RUN ************
+prog -help
+
+# OUTPUT
+command cat >&2 <<-'EOF'
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+EOF
+exit 0
+
+# RUN_OUTPUT
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+************ RUN ************
+prog -h
+
+# OUTPUT
+command cat >&2 <<-'EOF'
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+EOF
+exit 0
+
+# RUN_OUTPUT
+prog 1.0.0
+nobody
+Test argc
+
+USAGE: prog
+
+************ RUN ************
+prog --version
+
+# OUTPUT
+command cat >&2 <<-'EOF'
+prog 1.0.0
+EOF
+exit 0
+
+# RUN_OUTPUT
+prog 1.0.0
+
+************ RUN ************
+prog -version
+
+# OUTPUT
+command cat >&2 <<-'EOF'
+prog 1.0.0
+EOF
+exit 0
+
+# RUN_OUTPUT
+prog 1.0.0
+
+************ RUN ************
+prog -V
+
+# OUTPUT
+command cat >&2 <<-'EOF'
+prog 1.0.0
+EOF
+exit 0
+
+# RUN_OUTPUT
+prog 1.0.0
diff --git a/tests/snapshots/integration__validate__version.snap b/tests/snapshots/integration__validate__version_missing.snap
similarity index 99%
rename from tests/snapshots/integration__validate__version.snap
rename to tests/snapshots/integration__validate__version_missing.snap
index f1c2bf4b..8e6b486b 100644
--- a/tests/snapshots/integration__validate__version.snap
+++ b/tests/snapshots/integration__validate__version_missing.snap
@@ -28,5 +28,3 @@ argc__args=([0]="prog" [1]="cmd" [2]="--version")
argc__fn=cmd
argc__positionals=([0]="--version")
cmd --version
-
-
diff --git a/tests/validate.rs b/tests/validate.rs
index 4019f15d..c146d677 100644
--- a/tests/validate.rs
+++ b/tests/validate.rs
@@ -4,8 +4,29 @@ use crate::*;
fn help_version() {
let script = r###"
# @describe Test argc
-# @version 1.0.0
-# @author nobody
+# @meta version 1.0.0
+# @meta author nobody
+"###;
+ snapshot_multi!(
+ script,
+ [
+ vec!["prog", "help"],
+ vec!["prog", "--help"],
+ vec!["prog", "-help"],
+ vec!["prog", "-h"],
+ vec!["prog", "--version"],
+ vec!["prog", "-version"],
+ vec!["prog", "-V"],
+ ]
+ );
+}
+
+#[test]
+fn help_version_legacy() {
+ let script = r###"
+# @describe Test argc
+# @version 1.0.0
+# @author nobody
"###;
snapshot_multi!(
script,
@@ -25,7 +46,7 @@ fn help_version() {
fn help_version_shadow() {
let script = r###"
# @describe Test argc
-# @version 1.0.0
+# @meta version 1.0.0
# @flag -h --host
# @flag -V --verify
@@ -37,7 +58,7 @@ fn help_version_shadow() {
fn help_version_exist() {
let script = r###"
# @describe Test argc
-# @version 1.0.0
+# @meta version 1.0.0
# @flag -h --help
# @flag -V --version
@@ -56,7 +77,7 @@ fn help_notations() {
}
#[test]
-fn version() {
+fn version_missing() {
let script = r###"
# @cmd
cmd() { :; }