@@ -139,6 +139,7 @@ class ReplDriver(settings: Array[String],
139139 // TODO: i5069
140140 final def bind (name : String , value : Any )(implicit state : State ): State = state
141141
142+ // redirecting the output allows us to test `println` in scripted tests
142143 private def withRedirectedOutput (op : => State ): State = {
143144 val savedOut = System .out
144145 val savedErr = System .err
@@ -238,19 +239,34 @@ class ReplDriver(settings: Array[String],
238239 allImports += (newState.objectIndex -> newImports)
239240 val newStateWithImports = newState.copy(imports = allImports)
240241
241- val warnings = newState.context.reporter.removeBufferedMessages(newState.context)
242- displayErrors(warnings)(newState) // display warnings
243- implicit val ctx = newState.context
244- if (! ctx.settings.XreplDisableDisplay .value)
245- displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports)
246- else
247- newStateWithImports
242+ val warnings = newState.context.reporter
243+ .removeBufferedMessages(newState.context)
244+ .map(rendering.formatError)
245+
246+ implicit val ctx : Context = newState.context
247+ val (updatedState, definitions) =
248+ if (! ctx.settings.XreplDisableDisplay .value)
249+ renderDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports)
250+ else
251+ (newStateWithImports, Seq .empty)
252+
253+ // output is printed in the order it was put in. warnings should be
254+ // shown before infos (eg. typedefs) for the same line. column
255+ // ordering is mostly to make tests deterministic
256+ implicit val diagnosticOrdering : Ordering [Diagnostic ] =
257+ Ordering [(Int , Int , Int )].on(d => (d.pos.line, - d.level, d.pos.column))
258+
259+ (definitions ++ warnings)
260+ .sorted
261+ .map(_.msg)
262+ .foreach(out.println)
263+
264+ updatedState
248265 }
249266 )
250267 }
251268
252- /** Display definitions from `tree` */
253- private def displayDefinitions (tree : tpd.Tree , newestWrapper : Name )(implicit state : State ): State = {
269+ private def renderDefinitions (tree : tpd.Tree , newestWrapper : Name )(implicit state : State ): (State , Seq [Diagnostic ]) = {
254270 implicit val ctx = state.context
255271
256272 def resAndUnit (denot : Denotation ) = {
@@ -264,7 +280,7 @@ class ReplDriver(settings: Array[String],
264280 name.startsWith(str.REPL_RES_PREFIX ) && hasValidNumber && sym.info == defn.UnitType
265281 }
266282
267- def displayMembers (symbol : Symbol ) = if (tree.symbol.info.exists) {
283+ def extractAndFormatMembers (symbol : Symbol ) : ( State , Seq [ Diagnostic ] ) = if (tree.symbol.info.exists) {
268284 val info = symbol.info
269285 val defs =
270286 info.bounds.hi.finalResultType
@@ -274,51 +290,47 @@ class ReplDriver(settings: Array[String],
274290 denot.symbol.owner == defn.ObjectClass ||
275291 denot.symbol.isConstructor
276292 }
277- .sortBy(_.name)
278293
279294 val vals =
280295 info.fields
281296 .filterNot(_.symbol.isOneOf(ParamAccessor | Private | Synthetic | Artifact | Module ))
282297 .filter(_.symbol.name.is(SimpleNameKind ))
283- .sortBy(_.name)
284298
285299 val typeAliases =
286- info.bounds.hi.typeMembers.filter(_.symbol.info.isTypeAlias).sortBy(_.name)
300+ info.bounds.hi.typeMembers.filter(_.symbol.info.isTypeAlias)
287301
288- (
289- typeAliases.map(" // defined alias " + _.symbol.showUser ) ++
302+ val formattedMembers =
303+ typeAliases.map(rendering.renderTypeAlias ) ++
290304 defs.map(rendering.renderMethod) ++
291- vals.map(rendering.renderVal).flatten
292- ).foreach(str => out.println(SyntaxHighlighting .highlight(str)))
305+ vals.flatMap(rendering.renderVal)
293306
294- state.copy(valIndex = state.valIndex - vals.count(resAndUnit))
307+ ( state.copy(valIndex = state.valIndex - vals.count(resAndUnit)), formattedMembers )
295308 }
296- else state
309+ else ( state, Seq .empty)
297310
298311 def isSyntheticCompanion (sym : Symbol ) =
299312 sym.is(Module ) && sym.is(Synthetic )
300313
301- def displayTypeDefs (sym : Symbol ) = sym.info.memberClasses
314+ def typeDefs (sym : Symbol ): Seq [ Diagnostic ] = sym.info.memberClasses
302315 .collect {
303316 case x if ! isSyntheticCompanion(x.symbol) && ! x.symbol.name.isReplWrapperName =>
304- x.symbol
317+ rendering.renderTypeDef(x)
305318 }
306- .foreach { sym =>
307- out.println(SyntaxHighlighting .highlight(" // defined " + sym.showUser))
308- }
309-
310319
311320 ctx.atPhase(ctx.typerPhase.next) {
312321 // Display members of wrapped module:
313322 tree.symbol.info.memberClasses
314323 .find(_.symbol.name == newestWrapper.moduleClassName)
315324 .map { wrapperModule =>
316- displayTypeDefs(wrapperModule.symbol)
317- displayMembers(wrapperModule.symbol)
325+ val formattedTypeDefs = typeDefs(wrapperModule.symbol)
326+ val (newState, formattedMembers) = extractAndFormatMembers(wrapperModule.symbol)
327+ val highlighted = (formattedTypeDefs ++ formattedMembers)
328+ .map(d => new Diagnostic (d.msg.mapMsg(SyntaxHighlighting .highlight), d.pos, d.level))
329+ (newState, highlighted)
318330 }
319331 .getOrElse {
320332 // user defined a trait/class/object, so no module needed
321- state
333+ ( state, Seq .empty)
322334 }
323335 }
324336 }
@@ -378,18 +390,9 @@ class ReplDriver(settings: Array[String],
378390 state
379391 }
380392
381- /** A `MessageRenderer` without file positions */
382- private val messageRenderer = new MessageRendering {
383- override def posStr (pos : SourcePosition , diagnosticLevel : String , message : Message )(implicit ctx : Context ): String = " "
384- }
385-
386- /** Render messages using the `MessageRendering` trait */
387- private def renderMessage (dia : Diagnostic ): Context => String =
388- messageRenderer.messageAndPos(dia.msg, dia.pos, messageRenderer.diagnosticLevel(dia))(_)
389-
390- /** Output errors to `out` */
393+ /** shows all errors nicely formatted */
391394 private def displayErrors (errs : Seq [Diagnostic ])(implicit state : State ): State = {
392- errs.map(renderMessage(_)(state.context) ).foreach(out.println)
395+ errs.map(rendering.formatError).map(_.msg ).foreach(out.println)
393396 state
394397 }
395398}
0 commit comments