Merge pull request #3739 from killerswan/usagemsg
Add a module to getopts for verbose option group declaration (and use it in rustc)
This commit is contained in:
commit
33adb7a824
4 changed files with 546 additions and 68 deletions
|
@ -203,6 +203,13 @@ pub pure fn connect(v: &[~str], sep: &str) -> ~str {
|
||||||
move s
|
move s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a string, make a new string with repeated copies of it
|
||||||
|
pub fn repeat(ss: &str, nn: uint) -> ~str {
|
||||||
|
let mut acc = ~"";
|
||||||
|
for nn.times { acc += ss; }
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Section: Adding to and removing from a string
|
Section: Adding to and removing from a string
|
||||||
*/
|
*/
|
||||||
|
@ -573,6 +580,40 @@ pub pure fn words(s: &str) -> ~[~str] {
|
||||||
split_nonempty(s, |c| char::is_whitespace(c))
|
split_nonempty(s, |c| char::is_whitespace(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Split a string into a vector of substrings,
|
||||||
|
* each of which is less than a limit
|
||||||
|
*/
|
||||||
|
pub fn split_within(ss: &str, lim: uint) -> ~[~str] {
|
||||||
|
let words = str::words(ss);
|
||||||
|
|
||||||
|
// empty?
|
||||||
|
if words == ~[] { return ~[]; }
|
||||||
|
|
||||||
|
let mut rows : ~[~str] = ~[];
|
||||||
|
let mut row : ~str = ~"";
|
||||||
|
|
||||||
|
for words.each |wptr| {
|
||||||
|
let word = *wptr;
|
||||||
|
|
||||||
|
// if adding this word to the row would go over the limit,
|
||||||
|
// then start a new row
|
||||||
|
if str::len(row) + str::len(word) + 1 > lim {
|
||||||
|
rows += [row]; // save previous row
|
||||||
|
row = word; // start a new one
|
||||||
|
} else {
|
||||||
|
if str::len(row) > 0 { row += ~" " } // separate words
|
||||||
|
row += word; // append to this row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the last row
|
||||||
|
if row != ~"" { rows += [row]; }
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Convert a string to lowercase. ASCII only
|
/// Convert a string to lowercase. ASCII only
|
||||||
pub pure fn to_lower(s: &str) -> ~str {
|
pub pure fn to_lower(s: &str) -> ~str {
|
||||||
map(s,
|
map(s,
|
||||||
|
@ -2479,6 +2520,18 @@ mod tests {
|
||||||
assert ~[] == words(~"");
|
assert ~[] == words(~"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_split_within() {
|
||||||
|
assert split_within(~"", 0) == ~[];
|
||||||
|
assert split_within(~"", 15) == ~[];
|
||||||
|
assert split_within(~"hello", 15) == ~[~"hello"];
|
||||||
|
|
||||||
|
let data = ~"\nMary had a little lamb\nLittle lamb\n";
|
||||||
|
assert split_within(data, 15) == ~[~"Mary had a little",
|
||||||
|
~"lamb Little",
|
||||||
|
~"lamb"];
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_str() {
|
fn test_find_str() {
|
||||||
// byte positions
|
// byte positions
|
||||||
|
@ -2554,6 +2607,15 @@ mod tests {
|
||||||
t(~[~"hi"], ~" ", ~"hi");
|
t(~[~"hi"], ~" ", ~"hi");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_repeat() {
|
||||||
|
assert repeat(~"x", 4) == ~"xxxx";
|
||||||
|
assert repeat(~"hi", 4) == ~"hihihihi";
|
||||||
|
assert repeat(~"ไท华", 3) == ~"ไท华ไท华ไท华";
|
||||||
|
assert repeat(~"", 4) == ~"";
|
||||||
|
assert repeat(~"hi", 0) == ~"";
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_to_upper() {
|
fn test_to_upper() {
|
||||||
// libc::toupper, and hence str::to_upper
|
// libc::toupper, and hence str::to_upper
|
||||||
|
|
|
@ -82,7 +82,7 @@ pub type Opt = {name: Name, hasarg: HasArg, occur: Occur};
|
||||||
|
|
||||||
fn mkname(nm: &str) -> Name {
|
fn mkname(nm: &str) -> Name {
|
||||||
let unm = str::from_slice(nm);
|
let unm = str::from_slice(nm);
|
||||||
return if str::len(nm) == 1u {
|
return if nm.len() == 1u {
|
||||||
Short(str::char_at(unm, 0u))
|
Short(str::char_at(unm, 0u))
|
||||||
} else { Long(unm) };
|
} else { Long(unm) };
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,22 @@ impl Occur : Eq {
|
||||||
pure fn ne(other: &Occur) -> bool { !self.eq(other) }
|
pure fn ne(other: &Occur) -> bool { !self.eq(other) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasArg : Eq {
|
||||||
|
pure fn eq(other: &HasArg) -> bool {
|
||||||
|
(self as uint) == ((*other) as uint)
|
||||||
|
}
|
||||||
|
pure fn ne(other: &HasArg) -> bool { !self.eq(other) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Opt : Eq {
|
||||||
|
pure fn eq(other: &Opt) -> bool {
|
||||||
|
self.name == (*other).name &&
|
||||||
|
self.hasarg == (*other).hasarg &&
|
||||||
|
self.occur == (*other).occur
|
||||||
|
}
|
||||||
|
pure fn ne(other: &Opt) -> bool { !self.eq(other) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Create an option that is required and takes an argument
|
/// Create an option that is required and takes an argument
|
||||||
pub fn reqopt(name: &str) -> Opt {
|
pub fn reqopt(name: &str) -> Opt {
|
||||||
return {name: mkname(name), hasarg: Yes, occur: Req};
|
return {name: mkname(name), hasarg: Yes, occur: Req};
|
||||||
|
@ -150,8 +166,29 @@ enum Optval { Val(~str), Given, }
|
||||||
*/
|
*/
|
||||||
pub type Matches = {opts: ~[Opt], vals: ~[~[Optval]], free: ~[~str]};
|
pub type Matches = {opts: ~[Opt], vals: ~[~[Optval]], free: ~[~str]};
|
||||||
|
|
||||||
|
impl Optval : Eq {
|
||||||
|
pure fn eq(other: &Optval) -> bool {
|
||||||
|
match self {
|
||||||
|
Val(ref s) => match *other { Val (ref os) => s == os,
|
||||||
|
Given => false },
|
||||||
|
Given => match *other { Val(_) => false,
|
||||||
|
Given => true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pure fn ne(other: &Optval) -> bool { !self.eq(other) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Matches : Eq {
|
||||||
|
pure fn eq(other: &Matches) -> bool {
|
||||||
|
self.opts == (*other).opts &&
|
||||||
|
self.vals == (*other).vals &&
|
||||||
|
self.free == (*other).free
|
||||||
|
}
|
||||||
|
pure fn ne(other: &Matches) -> bool { !self.eq(other) }
|
||||||
|
}
|
||||||
|
|
||||||
fn is_arg(arg: &str) -> bool {
|
fn is_arg(arg: &str) -> bool {
|
||||||
return str::len(arg) > 1u && arg[0] == '-' as u8;
|
return arg.len() > 1u && arg[0] == '-' as u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name_str(nm: &Name) -> ~str {
|
fn name_str(nm: &Name) -> ~str {
|
||||||
|
@ -177,6 +214,35 @@ pub enum Fail_ {
|
||||||
UnexpectedArgument(~str),
|
UnexpectedArgument(~str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Fail_ : Eq {
|
||||||
|
// this whole thing should be easy to infer...
|
||||||
|
pure fn eq(other: &Fail_) -> bool {
|
||||||
|
match self {
|
||||||
|
ArgumentMissing(ref s) => {
|
||||||
|
match *other { ArgumentMissing(ref so) => s == so,
|
||||||
|
_ => false }
|
||||||
|
}
|
||||||
|
UnrecognizedOption(ref s) => {
|
||||||
|
match *other { UnrecognizedOption(ref so) => s == so,
|
||||||
|
_ => false }
|
||||||
|
}
|
||||||
|
OptionMissing(ref s) => {
|
||||||
|
match *other { OptionMissing(ref so) => s == so,
|
||||||
|
_ => false }
|
||||||
|
}
|
||||||
|
OptionDuplicated(ref s) => {
|
||||||
|
match *other { OptionDuplicated(ref so) => s == so,
|
||||||
|
_ => false }
|
||||||
|
}
|
||||||
|
UnexpectedArgument(ref s) => {
|
||||||
|
match *other { UnexpectedArgument(ref so) => s == so,
|
||||||
|
_ => false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pure fn ne(other: &Fail_) -> bool { !self.eq(other) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert a `fail_` enum into an error string
|
/// Convert a `fail_` enum into an error string
|
||||||
pub fn fail_str(f: Fail_) -> ~str {
|
pub fn fail_str(f: Fail_) -> ~str {
|
||||||
return match f {
|
return match f {
|
||||||
|
@ -220,7 +286,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result unsafe {
|
||||||
let mut i = 0u;
|
let mut i = 0u;
|
||||||
while i < l {
|
while i < l {
|
||||||
let cur = args[i];
|
let cur = args[i];
|
||||||
let curlen = str::len(cur);
|
let curlen = cur.len();
|
||||||
if !is_arg(cur) {
|
if !is_arg(cur) {
|
||||||
free.push(cur);
|
free.push(cur);
|
||||||
} else if cur == ~"--" {
|
} else if cur == ~"--" {
|
||||||
|
@ -444,6 +510,194 @@ impl FailType : Eq {
|
||||||
pure fn ne(other: &FailType) -> bool { !self.eq(other) }
|
pure fn ne(other: &FailType) -> bool { !self.eq(other) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A module which provides a way to specify descriptions and
|
||||||
|
* groups of short and long option names, together.
|
||||||
|
*/
|
||||||
|
pub mod groups {
|
||||||
|
|
||||||
|
/** one group of options, e.g., both -h and --help, along with
|
||||||
|
* their shared description and properties
|
||||||
|
*/
|
||||||
|
pub type OptGroup = {
|
||||||
|
short_name: ~str,
|
||||||
|
long_name: ~str,
|
||||||
|
hint: ~str,
|
||||||
|
desc: ~str,
|
||||||
|
hasarg: HasArg,
|
||||||
|
occur: Occur
|
||||||
|
};
|
||||||
|
|
||||||
|
impl OptGroup : Eq {
|
||||||
|
pure fn eq(other: &OptGroup) -> bool {
|
||||||
|
self.short_name == (*other).short_name &&
|
||||||
|
self.long_name == (*other).long_name &&
|
||||||
|
self.hint == (*other).hint &&
|
||||||
|
self.desc == (*other).desc &&
|
||||||
|
self.hasarg == (*other).hasarg &&
|
||||||
|
self.occur == (*other).occur
|
||||||
|
}
|
||||||
|
pure fn ne(other: &OptGroup) -> bool { !self.eq(other) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a long option that is required and takes an argument
|
||||||
|
pub fn reqopt(short_name: &str, long_name: &str,
|
||||||
|
desc: &str, hint: &str) -> OptGroup {
|
||||||
|
let len = short_name.len();
|
||||||
|
assert len == 1 || len == 0;
|
||||||
|
return {short_name: str::from_slice(short_name),
|
||||||
|
long_name: str::from_slice(long_name),
|
||||||
|
hint: str::from_slice(hint),
|
||||||
|
desc: str::from_slice(desc),
|
||||||
|
hasarg: Yes,
|
||||||
|
occur: Req};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a long option that is optional and takes an argument
|
||||||
|
pub fn optopt(short_name: &str, long_name: &str,
|
||||||
|
desc: &str, hint: &str) -> OptGroup {
|
||||||
|
let len = short_name.len();
|
||||||
|
assert len == 1 || len == 0;
|
||||||
|
return {short_name: str::from_slice(short_name),
|
||||||
|
long_name: str::from_slice(long_name),
|
||||||
|
hint: str::from_slice(hint),
|
||||||
|
desc: str::from_slice(desc),
|
||||||
|
hasarg: Yes,
|
||||||
|
occur: Optional};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a long option that is optional and does not take an argument
|
||||||
|
pub fn optflag(short_name: &str, long_name: &str,
|
||||||
|
desc: &str) -> OptGroup {
|
||||||
|
let len = short_name.len();
|
||||||
|
assert len == 1 || len == 0;
|
||||||
|
return {short_name: str::from_slice(short_name),
|
||||||
|
long_name: str::from_slice(long_name),
|
||||||
|
hint: ~"",
|
||||||
|
desc: str::from_slice(desc),
|
||||||
|
hasarg: No,
|
||||||
|
occur: Optional};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a long option that is optional and takes an optional argument
|
||||||
|
pub fn optflagopt(short_name: &str, long_name: &str,
|
||||||
|
desc: &str, hint: &str) -> OptGroup {
|
||||||
|
let len = short_name.len();
|
||||||
|
assert len == 1 || len == 0;
|
||||||
|
return {short_name: str::from_slice(short_name),
|
||||||
|
long_name: str::from_slice(long_name),
|
||||||
|
hint: str::from_slice(hint),
|
||||||
|
desc: str::from_slice(desc),
|
||||||
|
hasarg: Maybe,
|
||||||
|
occur: Optional};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a long option that is optional, takes an argument, and may occur
|
||||||
|
* multiple times
|
||||||
|
*/
|
||||||
|
pub fn optmulti(short_name: &str, long_name: &str,
|
||||||
|
desc: &str, hint: &str) -> OptGroup {
|
||||||
|
let len = short_name.len();
|
||||||
|
assert len == 1 || len == 0;
|
||||||
|
return {short_name: str::from_slice(short_name),
|
||||||
|
long_name: str::from_slice(long_name),
|
||||||
|
hint: str::from_slice(hint),
|
||||||
|
desc: str::from_slice(desc),
|
||||||
|
hasarg: Yes,
|
||||||
|
occur: Multi};
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate OptGroup into Opt
|
||||||
|
// (both short and long names correspond to different Opts)
|
||||||
|
pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] {
|
||||||
|
match ((*lopt).short_name.len(),
|
||||||
|
(*lopt).long_name.len()) {
|
||||||
|
|
||||||
|
(0,0) => fail ~"this long-format option was given no name",
|
||||||
|
|
||||||
|
(0,_) => ~[{name: Long(((*lopt).long_name)),
|
||||||
|
hasarg: (*lopt).hasarg,
|
||||||
|
occur: (*lopt).occur}],
|
||||||
|
|
||||||
|
(1,0) => ~[{name: Short(str::char_at((*lopt).short_name, 0)),
|
||||||
|
hasarg: (*lopt).hasarg,
|
||||||
|
occur: (*lopt).occur}],
|
||||||
|
|
||||||
|
(1,_) => ~[{name: Short(str::char_at((*lopt).short_name, 0)),
|
||||||
|
hasarg: (*lopt).hasarg,
|
||||||
|
occur: (*lopt).occur},
|
||||||
|
{name: Long(((*lopt).long_name)),
|
||||||
|
hasarg: (*lopt).hasarg,
|
||||||
|
occur: (*lopt).occur}],
|
||||||
|
|
||||||
|
(_,_) => fail ~"something is wrong with the long-form opt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse command line args with the provided long format options
|
||||||
|
*/
|
||||||
|
pub fn getopts(args: &[~str], opts: &[OptGroup]) -> Result {
|
||||||
|
::getopts::getopts(args, vec::flat_map(opts, long_to_short))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive a usage message from a set of long options
|
||||||
|
*/
|
||||||
|
pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
|
||||||
|
|
||||||
|
let desc_sep = ~"\n" + str::repeat(~" ", 24);
|
||||||
|
|
||||||
|
let rows = vec::map(opts, |optref| {
|
||||||
|
let short_name = (*optref).short_name;
|
||||||
|
let long_name = (*optref).long_name;
|
||||||
|
let hint = (*optref).hint;
|
||||||
|
let desc = (*optref).desc;
|
||||||
|
let hasarg = (*optref).hasarg;
|
||||||
|
|
||||||
|
let mut row = str::repeat(~" ", 4);
|
||||||
|
|
||||||
|
// short option
|
||||||
|
row += match short_name.len() {
|
||||||
|
0 => ~"",
|
||||||
|
1 => ~"-" + short_name + " ",
|
||||||
|
_ => fail ~"the short name should only be 1 char long",
|
||||||
|
};
|
||||||
|
|
||||||
|
// long option
|
||||||
|
row += match long_name.len() {
|
||||||
|
0 => ~"",
|
||||||
|
_ => ~"--" + long_name + " ",
|
||||||
|
};
|
||||||
|
|
||||||
|
// arg
|
||||||
|
row += match hasarg {
|
||||||
|
No => ~"",
|
||||||
|
Yes => hint,
|
||||||
|
Maybe => ~"[" + hint + ~"]",
|
||||||
|
};
|
||||||
|
|
||||||
|
// here we just need to indent the start of the description
|
||||||
|
let rowlen = row.len();
|
||||||
|
row += if rowlen < 24 {
|
||||||
|
str::repeat(~" ", 24 - rowlen)
|
||||||
|
} else {
|
||||||
|
desc_sep
|
||||||
|
};
|
||||||
|
|
||||||
|
// wrapped description
|
||||||
|
row += str::connect(str::split_within(desc, 54), desc_sep);
|
||||||
|
|
||||||
|
row
|
||||||
|
});
|
||||||
|
|
||||||
|
return str::from_slice(brief) +
|
||||||
|
~"\n\nOptions:\n" +
|
||||||
|
str::connect(rows, ~"\n") +
|
||||||
|
~"\n\n";
|
||||||
|
}
|
||||||
|
} // end groups module
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[legacy_exports];
|
#[legacy_exports];
|
||||||
|
@ -943,6 +1197,158 @@ mod tests {
|
||||||
assert opts_present(matches, ~[~"L"]);
|
assert opts_present(matches, ~[~"L"]);
|
||||||
assert opts_str(matches, ~[~"L"]) == ~"foo";
|
assert opts_str(matches, ~[~"L"]) == ~"foo";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_reqopt() {
|
||||||
|
let opt = groups::reqopt(~"b", ~"banana", ~"some bananas", ~"VAL");
|
||||||
|
assert opt == { short_name: ~"b",
|
||||||
|
long_name: ~"banana",
|
||||||
|
hint: ~"VAL",
|
||||||
|
desc: ~"some bananas",
|
||||||
|
hasarg: Yes,
|
||||||
|
occur: Req }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_optopt() {
|
||||||
|
let opt = groups::optopt(~"a", ~"apple", ~"some apples", ~"VAL");
|
||||||
|
assert opt == { short_name: ~"a",
|
||||||
|
long_name: ~"apple",
|
||||||
|
hint: ~"VAL",
|
||||||
|
desc: ~"some apples",
|
||||||
|
hasarg: Yes,
|
||||||
|
occur: Optional }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_optflag() {
|
||||||
|
let opt = groups::optflag(~"k", ~"kiwi", ~"some kiwis");
|
||||||
|
assert opt == { short_name: ~"k",
|
||||||
|
long_name: ~"kiwi",
|
||||||
|
hint: ~"",
|
||||||
|
desc: ~"some kiwis",
|
||||||
|
hasarg: No,
|
||||||
|
occur: Optional }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_optflagopt() {
|
||||||
|
let opt = groups::optflagopt(~"p", ~"pineapple",
|
||||||
|
~"some pineapples", ~"VAL");
|
||||||
|
assert opt == { short_name: ~"p",
|
||||||
|
long_name: ~"pineapple",
|
||||||
|
hint: ~"VAL",
|
||||||
|
desc: ~"some pineapples",
|
||||||
|
hasarg: Maybe,
|
||||||
|
occur: Optional }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_optmulti() {
|
||||||
|
let opt = groups::optmulti(~"l", ~"lime",
|
||||||
|
~"some limes", ~"VAL");
|
||||||
|
assert opt == { short_name: ~"l",
|
||||||
|
long_name: ~"lime",
|
||||||
|
hint: ~"VAL",
|
||||||
|
desc: ~"some limes",
|
||||||
|
hasarg: Yes,
|
||||||
|
occur: Multi }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_long_to_short() {
|
||||||
|
let short = ~[reqopt(~"b"), reqopt(~"banana")];
|
||||||
|
let verbose = groups::reqopt(~"b", ~"banana",
|
||||||
|
~"some bananas", ~"VAL");
|
||||||
|
|
||||||
|
assert groups::long_to_short(&verbose) == short;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_getopts() {
|
||||||
|
let short = ~[
|
||||||
|
reqopt(~"b"), reqopt(~"banana"),
|
||||||
|
optopt(~"a"), optopt(~"apple"),
|
||||||
|
optflag(~"k"), optflagopt(~"kiwi"),
|
||||||
|
optflagopt(~"p"),
|
||||||
|
optmulti(~"l")
|
||||||
|
];
|
||||||
|
|
||||||
|
let verbose = ~[
|
||||||
|
groups::reqopt(~"b", ~"banana", ~"Desc", ~"VAL"),
|
||||||
|
groups::optopt(~"a", ~"apple", ~"Desc", ~"VAL"),
|
||||||
|
groups::optflag(~"k", ~"kiwi", ~"Desc"),
|
||||||
|
groups::optflagopt(~"p", ~"", ~"Desc", ~"VAL"),
|
||||||
|
groups::optmulti(~"l", ~"", ~"Desc", ~"VAL"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k",
|
||||||
|
~"-p", ~"16", ~"l", ~"35"];
|
||||||
|
|
||||||
|
// NOTE: we should sort before comparing
|
||||||
|
assert getopts(sample_args, short)
|
||||||
|
== groups::getopts(sample_args, verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_usage() {
|
||||||
|
let optgroups = ~[
|
||||||
|
groups::reqopt(~"b", ~"banana", ~"Desc", ~"VAL"),
|
||||||
|
groups::optopt(~"a", ~"012345678901234567890123456789",
|
||||||
|
~"Desc", ~"VAL"),
|
||||||
|
groups::optflag(~"k", ~"kiwi", ~"Desc"),
|
||||||
|
groups::optflagopt(~"p", ~"", ~"Desc", ~"VAL"),
|
||||||
|
groups::optmulti(~"l", ~"", ~"Desc", ~"VAL"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
~"Usage: fruits
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-b --banana VAL Desc
|
||||||
|
-a --012345678901234567890123456789 VAL
|
||||||
|
Desc
|
||||||
|
-k --kiwi Desc
|
||||||
|
-p [VAL] Desc
|
||||||
|
-l VAL Desc
|
||||||
|
|
||||||
|
";
|
||||||
|
|
||||||
|
let generated_usage = groups::usage(~"Usage: fruits", optgroups);
|
||||||
|
|
||||||
|
debug!("expected: <<%s>>", expected);
|
||||||
|
debug!("generated: <<%s>>", generated_usage);
|
||||||
|
assert generated_usage == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groups_usage_description_wrapping() {
|
||||||
|
// indentation should be 24 spaces
|
||||||
|
// lines wrap after 78: or rather descriptions wrap after 54
|
||||||
|
|
||||||
|
let optgroups = ~[
|
||||||
|
groups::optflag(~"k", ~"kiwi",
|
||||||
|
~"This is a long description which won't be wrapped..+.."), // 54
|
||||||
|
groups::optflag(~"a", ~"apple",
|
||||||
|
~"This is a long description which _will_ be wrapped..+.."), // 55
|
||||||
|
];
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
~"Usage: fruits
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-k --kiwi This is a long description which won't be wrapped..+..
|
||||||
|
-a --apple This is a long description which _will_ be
|
||||||
|
wrapped..+..
|
||||||
|
|
||||||
|
";
|
||||||
|
|
||||||
|
let usage = groups::usage(~"Usage: fruits", optgroups);
|
||||||
|
|
||||||
|
debug!("expected: <<%s>>", expected);
|
||||||
|
debug!("generated: <<%s>>", usage);
|
||||||
|
assert usage == expected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
|
|
|
@ -10,8 +10,10 @@ use util::ppaux;
|
||||||
use back::link;
|
use back::link;
|
||||||
use result::{Ok, Err};
|
use result::{Ok, Err};
|
||||||
use std::getopts;
|
use std::getopts;
|
||||||
|
use std::getopts::{opt_present};
|
||||||
|
use std::getopts::groups;
|
||||||
|
use std::getopts::groups::{optopt, optmulti, optflag, optflagopt, getopts};
|
||||||
use io::WriterUtil;
|
use io::WriterUtil;
|
||||||
use getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
|
|
||||||
use back::{x86, x86_64};
|
use back::{x86, x86_64};
|
||||||
use std::map::HashMap;
|
use std::map::HashMap;
|
||||||
use lib::llvm::llvm;
|
use lib::llvm::llvm;
|
||||||
|
@ -623,27 +625,69 @@ fn parse_pretty(sess: Session, &&name: ~str) -> pp_mode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opts() -> ~[getopts::Opt] {
|
// rustc command line options
|
||||||
return ~[optflag(~"h"), optflag(~"help"),
|
fn optgroups() -> ~[getopts::groups::OptGroup] {
|
||||||
optflag(~"v"), optflag(~"version"),
|
~[
|
||||||
optflag(~"emit-llvm"), optflagopt(~"pretty"),
|
optflag(~"", ~"bin", ~"Compile an executable crate (default)"),
|
||||||
optflag(~"ls"), optflag(~"parse-only"), optflag(~"no-trans"),
|
optflag(~"c", ~"", ~"Compile and assemble, but do not link"),
|
||||||
optflag(~"O"), optopt(~"opt-level"), optmulti(~"L"), optflag(~"S"),
|
optmulti(~"", ~"cfg", ~"Configure the compilation
|
||||||
optopt(~"o"), optopt(~"out-dir"), optflag(~"xg"),
|
environment", ~"SPEC"),
|
||||||
optflag(~"c"), optflag(~"g"), optflag(~"save-temps"),
|
optflag(~"", ~"emit-llvm",
|
||||||
optopt(~"sysroot"), optopt(~"target"),
|
~"Produce an LLVM bitcode file"),
|
||||||
optflag(~"jit"),
|
optflag(~"g", ~"", ~"Produce debug info (experimental)"),
|
||||||
|
optflag(~"", ~"gc", ~"Garbage collect shared data (experimental)"),
|
||||||
optmulti(~"W"), optmulti(~"warn"),
|
optflag(~"h", ~"help",~"Display this message"),
|
||||||
optmulti(~"A"), optmulti(~"allow"),
|
optmulti(~"L", ~"", ~"Add a directory to the library search path",
|
||||||
optmulti(~"D"), optmulti(~"deny"),
|
~"PATH"),
|
||||||
optmulti(~"F"), optmulti(~"forbid"),
|
optflag(~"", ~"lib", ~"Compile a library crate"),
|
||||||
|
optflag(~"", ~"ls", ~"List the symbols defined by a library crate"),
|
||||||
optmulti(~"Z"),
|
optflag(~"", ~"jit", ~"Execute using JIT (experimental)"),
|
||||||
|
optflag(~"", ~"no-trans",
|
||||||
optmulti(~"cfg"), optflag(~"test"),
|
~"Run all passes except translation; no output"),
|
||||||
optflag(~"lib"), optflag(~"bin"),
|
optflag(~"O", ~"", ~"Equivalent to --opt-level=2"),
|
||||||
optflag(~"static"), optflag(~"gc")];
|
optopt(~"o", ~"", ~"Write output to <filename>", ~"FILENAME"),
|
||||||
|
optopt(~"", ~"opt-level",
|
||||||
|
~"Optimize with possible levels 0-3", ~"LEVEL"),
|
||||||
|
optopt( ~"", ~"out-dir",
|
||||||
|
~"Write output to compiler-chosen filename
|
||||||
|
in <dir>", ~"DIR"),
|
||||||
|
optflag(~"", ~"parse-only",
|
||||||
|
~"Parse only; do not compile, assemble, or link"),
|
||||||
|
optflagopt(~"", ~"pretty",
|
||||||
|
~"Pretty-print the input instead of compiling;
|
||||||
|
valid types are: normal (un-annotated source),
|
||||||
|
expanded (crates expanded),
|
||||||
|
typed (crates expanded, with type annotations),
|
||||||
|
or identified (fully parenthesized,
|
||||||
|
AST nodes and blocks with IDs)", ~"TYPE"),
|
||||||
|
optflag(~"S", ~"", ~"Compile only; do not assemble or link"),
|
||||||
|
optflag(~"", ~"xg", ~"Extra debugging info (experimental)"),
|
||||||
|
optflag(~"", ~"save-temps",
|
||||||
|
~"Write intermediate files (.bc, .opt.bc, .o)
|
||||||
|
in addition to normal output"),
|
||||||
|
optflag(~"", ~"static",
|
||||||
|
~"Use or produce static libraries or binaries
|
||||||
|
(experimental)"),
|
||||||
|
optopt(~"", ~"sysroot",
|
||||||
|
~"Override the system root", ~"PATH"),
|
||||||
|
optflag(~"", ~"test", ~"Build a test harness"),
|
||||||
|
optopt(~"", ~"target",
|
||||||
|
~"Target triple cpu-manufacturer-kernel[-os]
|
||||||
|
to compile for (see
|
||||||
|
http://sources.redhat.com/autobook/autobook/autobook_17.html
|
||||||
|
for detail)", ~"TRIPLE"),
|
||||||
|
optmulti(~"W", ~"warn",
|
||||||
|
~"Set lint warnings", ~"OPT"),
|
||||||
|
optmulti(~"A", ~"allow",
|
||||||
|
~"Set lint allowed", ~"OPT"),
|
||||||
|
optmulti(~"D", ~"deny",
|
||||||
|
~"Set lint denied", ~"OPT"),
|
||||||
|
optmulti(~"F", ~"forbid",
|
||||||
|
~"Set lint forbidden", ~"OPT"),
|
||||||
|
optmulti(~"Z", ~"", ~"Set internal debugging options", "FLAG"),
|
||||||
|
optflag( ~"v", ~"version",
|
||||||
|
~"Print version info and exit"),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
type output_filenames = @{out_filename:Path, obj_filename:Path};
|
type output_filenames = @{out_filename:Path, obj_filename:Path};
|
||||||
|
@ -741,7 +785,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_switch_implies_cfg_test() {
|
fn test_switch_implies_cfg_test() {
|
||||||
let matches =
|
let matches =
|
||||||
match getopts::getopts(~[~"--test"], opts()) {
|
match getopts(~[~"--test"], optgroups()) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(f) => fail ~"test_switch_implies_cfg_test: " +
|
Err(f) => fail ~"test_switch_implies_cfg_test: " +
|
||||||
getopts::fail_str(f)
|
getopts::fail_str(f)
|
||||||
|
@ -758,7 +802,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_switch_implies_cfg_test_unless_cfg_test() {
|
fn test_switch_implies_cfg_test_unless_cfg_test() {
|
||||||
let matches =
|
let matches =
|
||||||
match getopts::getopts(~[~"--test", ~"--cfg=test"], opts()) {
|
match getopts(~[~"--test", ~"--cfg=test"], optgroups()) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(f) => {
|
Err(f) => {
|
||||||
fail ~"test_switch_implies_cfg_test_unless_cfg_test: " +
|
fail ~"test_switch_implies_cfg_test_unless_cfg_test: " +
|
||||||
|
|
|
@ -16,6 +16,7 @@ use io::ReaderUtil;
|
||||||
use std::getopts;
|
use std::getopts;
|
||||||
use std::map::HashMap;
|
use std::map::HashMap;
|
||||||
use getopts::{opt_present};
|
use getopts::{opt_present};
|
||||||
|
use getopts::groups;
|
||||||
use rustc::driver::driver::*;
|
use rustc::driver::driver::*;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
use syntax::diagnostic;
|
use syntax::diagnostic;
|
||||||
|
@ -31,46 +32,11 @@ fn version(argv0: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(argv0: &str) {
|
fn usage(argv0: &str) {
|
||||||
io::println(fmt!("Usage: %s [options] <input>\n", argv0) +
|
let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
|
||||||
~"
|
io::println(groups::usage(message, optgroups()) +
|
||||||
Options:
|
~"Additional help:
|
||||||
|
-W help Print 'lint' options and default settings
|
||||||
--bin Compile an executable crate (default)
|
-Z help Print internal options for debugging rustc
|
||||||
-c Compile and assemble, but do not link
|
|
||||||
--cfg <cfgspec> Configure the compilation environment
|
|
||||||
--emit-llvm Produce an LLVM bitcode file
|
|
||||||
-g Produce debug info (experimental)
|
|
||||||
--gc Garbage collect shared data (experimental/temporary)
|
|
||||||
-h --help Display this message
|
|
||||||
-L <path> Add a directory to the library search path
|
|
||||||
--lib Compile a library crate
|
|
||||||
--ls List the symbols defined by a compiled library crate
|
|
||||||
--jit Execute using JIT (experimental)
|
|
||||||
--no-trans Run all passes except translation; no output
|
|
||||||
-O Equivalent to --opt-level=2
|
|
||||||
-o <filename> Write output to <filename>
|
|
||||||
--opt-level <lvl> Optimize with possible levels 0-3
|
|
||||||
--out-dir <dir> Write output to compiler-chosen filename in <dir>
|
|
||||||
--parse-only Parse only; do not compile, assemble, or link
|
|
||||||
--pretty [type] Pretty-print the input instead of compiling;
|
|
||||||
valid types are: normal (un-annotated source),
|
|
||||||
expanded (crates expanded), typed (crates expanded,
|
|
||||||
with type annotations), or identified (fully
|
|
||||||
parenthesized, AST nodes and blocks with IDs)
|
|
||||||
-S Compile only; do not assemble or link
|
|
||||||
--save-temps Write intermediate files (.bc, .opt.bc, .o)
|
|
||||||
in addition to normal output
|
|
||||||
--static Use or produce static libraries or binaries
|
|
||||||
(experimental)
|
|
||||||
--sysroot <path> Override the system root
|
|
||||||
--test Build a test harness
|
|
||||||
--target <triple> Target cpu-manufacturer-kernel[-os] to compile for
|
|
||||||
(default: host triple)
|
|
||||||
(see http://sources.redhat.com/autobook/autobook/
|
|
||||||
autobook_17.html for detail)
|
|
||||||
-W help Print 'lint' options and default settings
|
|
||||||
-Z help Print internal options for debugging rustc
|
|
||||||
-v --version Print version info and exit
|
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +93,7 @@ fn run_compiler(args: &~[~str], demitter: diagnostic::emitter) {
|
||||||
if args.is_empty() { usage(binary); return; }
|
if args.is_empty() { usage(binary); return; }
|
||||||
|
|
||||||
let matches =
|
let matches =
|
||||||
match getopts::getopts(args, opts()) {
|
match getopts::groups::getopts(args, optgroups()) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(f) => {
|
Err(f) => {
|
||||||
early_error(demitter, getopts::fail_str(f))
|
early_error(demitter, getopts::fail_str(f))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue