@@ -39,18 +39,12 @@ object Settings:
3939 this
4040 end SettingsState
4141
42- case class ArgsSummary (
43- sstate : SettingsState ,
44- arguments : List [String ],
45- errors : List [String ],
46- warnings : List [String ]) {
42+ case class ArgsSummary (sstate : SettingsState , arguments : List [String ], errors : List [String ], warnings : List [String ])
4743
48- def fail (msg : String ): Settings .ArgsSummary =
49- ArgsSummary (sstate, arguments.tail, errors :+ msg, warnings)
50-
51- def warn (msg : String ): Settings .ArgsSummary =
52- ArgsSummary (sstate, arguments.tail, errors, warnings :+ msg)
53- }
44+ extension (summary : ArgsSummary )
45+ def fail (msg : String ): ArgsSummary = summary.copy(errors = summary.errors :+ msg)
46+ def warn (msg : String ): ArgsSummary = summary.copy(warnings = summary.warnings :+ msg)
47+ def skip (): ArgsSummary = summary.copy(arguments = if summary.arguments.isEmpty then Nil else summary.arguments.tail)
5448
5549 case class Setting [T : ClassTag ] private [Settings ] (
5650 name : String ,
@@ -73,7 +67,7 @@ object Settings:
7367
7468 def isDefaultIn (state : SettingsState ): Boolean = valueIn(state) == default
7569
76- def isMultivalue : Boolean = implicitly [ClassTag [T ]] == ListTag
70+ def isMultivalue : Boolean = summon [ClassTag [T ]] == ListTag
7771
7872 def legalChoices : String =
7973 choices match {
@@ -86,91 +80,92 @@ object Settings:
8680 def tryToSet (state : ArgsSummary ): ArgsSummary = {
8781 val ArgsSummary (sstate, arg :: args, errors, warnings) = state
8882 def update (value : Any , args : List [String ]): ArgsSummary =
89- var dangers = warnings
9083 val value1 =
91- if changed && isMultivalue then
92- val value0 = value.asInstanceOf [List [String ]]
93- val current = valueIn(sstate).asInstanceOf [List [String ]]
94- value0.filter(current.contains).foreach(s => dangers :+= s " Setting $name set to $s redundantly " )
95- current ++ value0
96- else
97- if changed then dangers :+= s " Flag $name set repeatedly "
98- value
84+ if isMultivalue then valueIn(sstate).asInstanceOf [List [String ]] ++ value.asInstanceOf [List [String ]]
85+ else value
9986 changed = true
100- ArgsSummary (updateIn(sstate, value1), args, errors, dangers)
101- end update
87+ ArgsSummary (updateIn(sstate, value1), args, errors, warnings)
88+
89+ def fail (msg : String , args : List [String ]) = ArgsSummary (sstate, args, errors :+ msg, warnings)
10290
103- def fail (msg : String , args : List [String ]) =
104- ArgsSummary (sstate, args, errors :+ msg, warnings)
91+ def missingArg = fail(s " missing argument for option $name" , args)
10592
106- def missingArg =
107- fail(s " missing argument for option $name" , args)
93+ def setBoolean (argValue : String ) =
94+ def checkAndSet (v : Boolean ) =
95+ val dubious = changed && v != valueIn(sstate).asInstanceOf [Boolean ]
96+ val updated = update(v, args)
97+ if dubious then updated.warn(s " Boolean flag $name flipped " ) else updated
98+ if argValue.equalsIgnoreCase(" true" ) || argValue == " " then checkAndSet(true )
99+ else if argValue.equalsIgnoreCase(" false" ) then checkAndSet(false )
100+ else fail(s " invalid boolean value $argValue" , args)
108101
109102 def setString (argValue : String , args : List [String ]) =
110103 choices match
111- case Some (xs) if ! xs.contains(argValue) =>
112- fail(s " $argValue is not a valid choice for $name" , args)
113- case _ =>
114- update(argValue, args)
104+ case Some (xs) if ! xs.contains(argValue) => fail(s " $argValue is not a valid choice for $name" , args)
105+ case _ if changed && argValue != valueIn(sstate).asInstanceOf [String ] => update(argValue, args).warn(s " Option $name was updated " )
106+ case _ => update(argValue, args)
115107
116108 def setInt (argValue : String , args : List [String ]) =
117109 try
118110 val x = argValue.toInt
119111 choices match
120- case Some (r : Range ) if x < r.head || r.last < x =>
121- fail(s " $argValue is out of legal range ${r.head} .. ${r.last} for $name" , args)
122- case Some (xs) if ! xs.contains(x) =>
123- fail(s " $argValue is not a valid choice for $name" , args)
124- case _ =>
125- update(x, args)
126- catch case _ : NumberFormatException =>
127- fail( s " $argValue is not an integer argument for $name " , args)
128-
129- def doSet ( argRest : String ) = ((implicitly[ ClassTag [ T ]], args) : @ unchecked) match {
130- case ( BooleanTag , _) =>
131- update( true , args)
132- case ( OptionTag , _) =>
133- update( Some (propertyClass.get.getConstructor().newInstance()), args)
134- case ( ListTag , _) =>
135- if (argRest.isEmpty) missingArg
136- else
137- val strings = argRest.split( " , " ).toList
138- choices match
139- case Some (valid) => strings .filterNot(valid.contains) match
140- case Nil => update(strings, args)
112+ case Some (r : Range ) if x < r.head || r.last < x => fail( s " $argValue is out of legal range ${r.head} .. ${r.last} for $name " , args)
113+ case Some (xs) if ! xs.contains(x) => fail(s " $argValue is not a valid choice for $name" , args)
114+ case _ => update(x, args)
115+ catch case _ : NumberFormatException => fail(s " $argValue is not an integer argument for $name" , args)
116+
117+ def doSet ( argRest : String ) : ArgsSummary = (summon[ ClassTag [ T ]] : @ unchecked) match {
118+ case BooleanTag => setBoolean(argRest)
119+ case OptionTag => update( Some (propertyClass.get.getConstructor().newInstance()) , args)
120+ case ListTag if argRest.isEmpty => missingArg
121+ case ListTag =>
122+ val split = argRest.split( " , " ).toList
123+ def checkRepeated =
124+ var dangers : List [ String ] = Nil
125+ if changed then
126+ val current = valueIn(sstate). asInstanceOf [ List [ String ]]
127+ split.filter(current.contains).foreach(s => dangers :+= s " Setting $name set to $s redundantly " )
128+ dangers.foldLeft(update(split, args))((sum, w) => sum.warn(w))
129+ choices match
130+ case Some (valid) =>
131+ split .filterNot(valid.contains) match
132+ case Nil => checkRepeated
141133 case invalid => fail(s " invalid choice(s) for $name: ${invalid.mkString(" ," )}" , args)
142- case _ => update(strings, args)
143- case (StringTag , _) if argRest.nonEmpty || choices.exists(_.contains(" " )) =>
144- setString(argRest, args)
145- case (StringTag , arg2 :: args2) =>
146- if (arg2 startsWith " -" ) missingArg
147- else setString(arg2, args2)
148- case (OutputTag , arg :: args) =>
149- val path = Directory (arg)
150- val isJar = path.extension == " jar"
151- if (! isJar && ! path.isDirectory)
152- fail(s " ' $arg' does not exist or is not a directory or .jar file " , args)
153- else {
154- val output = if (isJar) JarArchive .create(path) else new PlainDirectory (path)
155- update(output, args)
156- }
157- case (IntTag , args) if argRest.nonEmpty =>
158- setInt(argRest, args)
159- case (IntTag , arg2 :: args2) =>
160- setInt(arg2, args2)
161- case (VersionTag , _) =>
134+ case _ => checkRepeated
135+ case StringTag if argRest.nonEmpty || choices.exists(_.contains(" " )) => setString(argRest, args)
136+ case StringTag =>
137+ args match
138+ case arg2 :: _ if arg2.startsWith(" -" ) => missingArg
139+ case arg2 :: args2 => setString(arg2, args2)
140+ case _ => missingArg
141+ case OutputTag =>
142+ args match
143+ case arg :: rest =>
144+ val path = Directory (arg)
145+ val isJar = path.extension == " jar"
146+ if (! isJar && ! path.isDirectory) fail(s " ' $arg' does not exist or is not a directory or .jar file " , rest)
147+ else
148+ val output = if (isJar) JarArchive .create(path) else new PlainDirectory (path)
149+ update(output, rest)
150+ case _ => missingArg
151+ case IntTag if argRest.nonEmpty => setInt(argRest, args)
152+ case IntTag =>
153+ args match
154+ case arg :: rest => setInt(arg, rest)
155+ case _ => missingArg
156+ case VersionTag =>
162157 ScalaVersion .parse(argRest) match {
163158 case Success (v) => update(v, args)
164- case Failure (ex ) => fail(ex .getMessage, args)
159+ case Failure (x ) => fail(x .getMessage, args)
165160 }
166- case (_, Nil ) =>
167- missingArg
161+ case _ => missingArg
168162 }
169163
170164 def matches (argName : String ) = (name :: aliases).exists(_ == argName)
171165
166+ // begin
172167 if (prefix != " " && arg.startsWith(prefix))
173- doSet(arg drop prefix.length)
168+ doSet(arg. drop( prefix.length) )
174169 else if (prefix == " " && matches(arg.takeWhile(_ != ':' )))
175170 doSet(arg.dropWhile(_ != ':' ).drop(1 ))
176171 else
@@ -237,7 +232,7 @@ object Settings:
237232 if state1 ne state then state1
238233 else loop(settings1)
239234 case Nil =>
240- state.warn(s " bad option ' $x' was ignored " )
235+ state.warn(s " bad option ' $x' was ignored " ).skip()
241236 processArguments(loop(allSettings.toList), processAll, skipped)
242237 case arg :: args =>
243238 if processAll then processArguments(stateWithArgs(args), processAll, skipped :+ arg)
0 commit comments