Repository: ajalt/mordant
Pull request #229 (2024-09-07 18:26:41)

Remove deprecations


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b0a9dd1a..d021372a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,9 +17,15 @@
 - **Breaking Change** `TerminalInterface.info` is now a method with parameters instead of a property.
 - **Breaking Change** Moved `Markdown` widget to separate `mordant-markdown` module, which is not included by default. If you use markdown rendering, you need to add that module to you dependencies.
 - In raw mode on POSIX systems, pressing the escape key once will now immediately return an `Escape` event. [(#193)](https://github.com/ajalt/mordant/issues/193)
+- Renamed `TerminalInfo.crClearsLine` to `supportsAnsiCursor`
+- Combined all `ColumnWidth` subclasses into a single class with factory methods. If you were using `ColumnWidth.Custom`, you should now use the `ColumnWidth` constructor.
+- The following `Terminal` methods are now extensions: `prompt()`, `info()`, `danger()`, `warning()`, `success()`, `muted()`
+- Renamed `Terminal.info` property to `Terminal.terminalInfo`
 
 ### Removed
 - Removed constructor overloads for `Terminal`. There is now one constructor with all default parameters. 
+- Removed `Terminal.colors`. All colors rendered with the terminal are now automatically downsampled.
+- Removed previously deprecated methods.
 
 ### Fixed
 - Fixed ConcurrentModificationException from progress bars when updated under very high concurrency [(#204)](https://github.com/ajalt/mordant/issues/204)
diff --git a/mordant-markdown/src/commonMain/kotlin/com/github/ajalt/mordant/markdown/Markdown.kt b/mordant-markdown/src/commonMain/kotlin/com/github/ajalt/mordant/markdown/Markdown.kt
index 7d489309..8cb64bbf 100644
--- a/mordant-markdown/src/commonMain/kotlin/com/github/ajalt/mordant/markdown/Markdown.kt
+++ b/mordant-markdown/src/commonMain/kotlin/com/github/ajalt/mordant/markdown/Markdown.kt
@@ -22,7 +22,7 @@ class Markdown(
     private var document: Widget? = null
     private fun document(t: Terminal): Widget {
         if (document == null) {
-            document = MarkdownRenderer(markdown, t.theme, showHtml, hyperlinks ?: t.info.ansiHyperLinks).render()
+            document = MarkdownRenderer(markdown, t.theme, showHtml, hyperlinks ?: t.terminalInfo.ansiHyperLinks).render()
         }
         return document!!
     }
diff --git a/mordant/api/mordant.api b/mordant/api/mordant.api
index 8742dca8..59a24f2a 100644
--- a/mordant/api/mordant.api
+++ b/mordant/api/mordant.api
@@ -1,6 +1,5 @@
 public abstract class com/github/ajalt/mordant/animation/Animation : com/github/ajalt/mordant/animation/StoppableAnimation {
-	public fun <init> (ZLcom/github/ajalt/mordant/terminal/Terminal;)V
-	public synthetic fun <init> (ZLcom/github/ajalt/mordant/terminal/Terminal;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun <init> (Lcom/github/ajalt/mordant/terminal/Terminal;)V
 	public final fun clear ()V
 	public final fun getTerminal ()Lcom/github/ajalt/mordant/terminal/Terminal;
 	protected abstract fun renderData (Ljava/lang/Object;)Lcom/github/ajalt/mordant/rendering/Widget;
@@ -9,37 +8,9 @@ public abstract class com/github/ajalt/mordant/animation/Animation : com/github/
 }
 
 public final class com/github/ajalt/mordant/animation/AnimationKt {
-	public static final fun animation (Lcom/github/ajalt/mordant/terminal/Terminal;ZLkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/animation/Animation;
-	public static synthetic fun animation$default (Lcom/github/ajalt/mordant/terminal/Terminal;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/mordant/animation/Animation;
-	public static final fun textAnimation (Lcom/github/ajalt/mordant/terminal/Terminal;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Ljava/lang/Integer;ZLkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/animation/Animation;
-	public static synthetic fun textAnimation$default (Lcom/github/ajalt/mordant/terminal/Terminal;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Ljava/lang/Integer;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/mordant/animation/Animation;
-}
-
-public final class com/github/ajalt/mordant/animation/ProgressAnimation {
-	public final fun advance (J)V
-	public static synthetic fun advance$default (Lcom/github/ajalt/mordant/animation/ProgressAnimation;JILjava/lang/Object;)V
-	public final fun clear ()V
-	public final fun restart ()V
-	public final fun start ()V
-	public final fun stop ()V
-	public final fun update ()V
-	public final fun update (I)V
-	public final fun update (J)V
-	public final fun update (JLjava/lang/Long;)V
-	public final fun updateTotal (Ljava/lang/Long;)V
-}
-
-public final class com/github/ajalt/mordant/animation/ProgressAnimationBuilder : com/github/ajalt/mordant/widgets/ProgressBuilder {
-	public final fun getAnimationFrameRate ()I
-	public final fun getHistoryLength ()F
-	public final fun getTextFrameRate ()I
-	public final fun setAnimationFrameRate (I)V
-	public final fun setHistoryLength (F)V
-	public final fun setTextFrameRate (I)V
-}
-
-public final class com/github/ajalt/mordant/animation/ProgressAnimationKt {
-	public static final fun progressAnimation (Lcom/github/ajalt/mordant/terminal/Terminal;Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/animation/ProgressAnimation;
+	public static final fun animation (Lcom/github/ajalt/mordant/terminal/Terminal;Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/animation/Animation;
+	public static final fun textAnimation (Lcom/github/ajalt/mordant/terminal/Terminal;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/animation/Animation;
+	public static synthetic fun textAnimation$default (Lcom/github/ajalt/mordant/terminal/Terminal;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/mordant/animation/Animation;
 }
 
 public abstract interface class com/github/ajalt/mordant/animation/Refreshable {
@@ -810,7 +781,6 @@ public final class com/github/ajalt/mordant/table/Borders : java/lang/Enum {
 	public static final field LEFT_TOP_RIGHT Lcom/github/ajalt/mordant/table/Borders;
 	public static final field NONE Lcom/github/ajalt/mordant/table/Borders;
 	public static final field RIGHT Lcom/github/ajalt/mordant/table/Borders;
-	public static final field TOM_BOTTOM Lcom/github/ajalt/mordant/table/Borders;
 	public static final field TOP Lcom/github/ajalt/mordant/table/Borders;
 	public static final field TOP_BOTTOM Lcom/github/ajalt/mordant/table/Borders;
 	public static final field TOP_RIGHT Lcom/github/ajalt/mordant/table/Borders;
@@ -838,13 +808,11 @@ public final class com/github/ajalt/mordant/table/CellBuilder$DefaultImpls {
 }
 
 public abstract interface class com/github/ajalt/mordant/table/CellStyleBuilder : com/github/ajalt/mordant/table/CellStyleBuilderBase {
-	public abstract fun getBorders ()Lcom/github/ajalt/mordant/table/Borders;
 	public abstract fun getCellBorders ()Lcom/github/ajalt/mordant/table/Borders;
 	public abstract fun getPadding ()Lcom/github/ajalt/mordant/widgets/Padding;
 	public abstract fun getVerticalAlign ()Lcom/github/ajalt/mordant/rendering/VerticalAlign;
 	public abstract fun padding (I)V
 	public abstract fun padding (Lkotlin/jvm/functions/Function1;)V
-	public abstract fun setBorders (Lcom/github/ajalt/mordant/table/Borders;)V
 	public abstract fun setCellBorders (Lcom/github/ajalt/mordant/table/Borders;)V
 	public abstract fun setPadding (Lcom/github/ajalt/mordant/widgets/Padding;)V
 	public abstract fun setVerticalAlign (Lcom/github/ajalt/mordant/rendering/VerticalAlign;)V
@@ -890,23 +858,15 @@ public abstract interface class com/github/ajalt/mordant/table/ColumnHolderBuild
 	public abstract fun setAddPaddingWidthToFixedWidth (Z)V
 }
 
-public abstract class com/github/ajalt/mordant/table/ColumnWidth {
-}
-
-public final class com/github/ajalt/mordant/table/ColumnWidth$Auto : com/github/ajalt/mordant/table/ColumnWidth {
-	public static final field INSTANCE Lcom/github/ajalt/mordant/table/ColumnWidth$Auto;
-	public fun equals (Ljava/lang/Object;)Z
-	public fun hashCode ()I
-	public fun toString ()Ljava/lang/String;
-}
-
-public final class com/github/ajalt/mordant/table/ColumnWidth$Custom : com/github/ajalt/mordant/table/ColumnWidth {
-	public fun <init> (Ljava/lang/Integer;Ljava/lang/Float;I)V
-	public final fun component1 ()Ljava/lang/Integer;
-	public final fun component2 ()Ljava/lang/Float;
-	public final fun component3 ()I
-	public final fun copy (Ljava/lang/Integer;Ljava/lang/Float;I)Lcom/github/ajalt/mordant/table/ColumnWidth$Custom;
-	public static synthetic fun copy$default (Lcom/github/ajalt/mordant/table/ColumnWidth$Custom;Ljava/lang/Integer;Ljava/lang/Float;IILjava/lang/Object;)Lcom/github/ajalt/mordant/table/ColumnWidth$Custom;
+public final class com/github/ajalt/mordant/table/ColumnWidth {
+	public static final field Companion Lcom/github/ajalt/mordant/table/ColumnWidth$Companion;
+	public fun <init> (ILjava/lang/Integer;Ljava/lang/Float;)V
+	public synthetic fun <init> (ILjava/lang/Integer;Ljava/lang/Float;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public final fun component1 ()I
+	public final fun component2 ()Ljava/lang/Integer;
+	public final fun component3 ()Ljava/lang/Float;
+	public final fun copy (ILjava/lang/Integer;Ljava/lang/Float;)Lcom/github/ajalt/mordant/table/ColumnWidth;
+	public static synthetic fun copy$default (Lcom/github/ajalt/mordant/table/ColumnWidth;ILjava/lang/Integer;Ljava/lang/Float;ILjava/lang/Object;)Lcom/github/ajalt/mordant/table/ColumnWidth;
 	public fun equals (Ljava/lang/Object;)Z
 	public final fun getExpandWeight ()Ljava/lang/Float;
 	public final fun getPriority ()I
@@ -915,17 +875,11 @@ public final class com/github/ajalt/mordant/table/ColumnWidth$Custom : com/githu
 	public fun toString ()Ljava/lang/String;
 }
 
-public final class com/github/ajalt/mordant/table/ColumnWidth$Expand : com/github/ajalt/mordant/table/ColumnWidth {
-	public fun <init> ()V
-	public fun <init> (F)V
-	public synthetic fun <init> (FILkotlin/jvm/internal/DefaultConstructorMarker;)V
-	public fun <init> (Ljava/lang/Number;)V
-	public final fun getWeight ()F
-}
-
-public final class com/github/ajalt/mordant/table/ColumnWidth$Fixed : com/github/ajalt/mordant/table/ColumnWidth {
-	public fun <init> (I)V
-	public final fun getWidth ()I
+public final class com/github/ajalt/mordant/table/ColumnWidth$Companion {
+	public final fun Expand (Ljava/lang/Number;)Lcom/github/ajalt/mordant/table/ColumnWidth;
+	public static synthetic fun Expand$default (Lcom/github/ajalt/mordant/table/ColumnWidth$Companion;Ljava/lang/Number;ILjava/lang/Object;)Lcom/github/ajalt/mordant/table/ColumnWidth;
+	public final fun Fixed (I)Lcom/github/ajalt/mordant/table/ColumnWidth;
+	public final fun getAuto ()Lcom/github/ajalt/mordant/table/ColumnWidth;
 }
 
 public final class com/github/ajalt/mordant/table/CsvQuoting : java/lang/Enum {
@@ -1023,12 +977,10 @@ public abstract interface class com/github/ajalt/mordant/table/TableBuilder : co
 	public abstract fun footer (Lkotlin/jvm/functions/Function1;)V
 	public abstract fun getBorderStyle ()Lcom/github/ajalt/mordant/rendering/TextStyle;
 	public abstract fun getBorderType ()Lcom/github/ajalt/mordant/rendering/BorderType;
-	public abstract fun getOuterBorder ()Z
 	public abstract fun getTableBorders ()Lcom/github/ajalt/mordant/table/Borders;
 	public abstract fun header (Lkotlin/jvm/functions/Function1;)V
 	public abstract fun setBorderStyle (Lcom/github/ajalt/mordant/rendering/TextStyle;)V
 	public abstract fun setBorderType (Lcom/github/ajalt/mordant/rendering/BorderType;)V
-	public abstract fun setOuterBorder (Z)V
 	public abstract fun setTableBorders (Lcom/github/ajalt/mordant/table/Borders;)V
 }
 
@@ -1046,12 +998,8 @@ public final class com/github/ajalt/mordant/table/TableCsvKt {
 }
 
 public final class com/github/ajalt/mordant/table/TableDslKt {
-	public static final fun column (ILkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/rendering/Widget;
-	public static synthetic fun column$default (ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/mordant/rendering/Widget;
 	public static final fun grid (Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/rendering/Widget;
 	public static final fun horizontalLayout (Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/rendering/Widget;
-	public static final fun row (ILkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/rendering/Widget;
-	public static synthetic fun row$default (ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/mordant/rendering/Widget;
 	public static final fun table (Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/table/Table;
 	public static final fun verticalLayout (Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/rendering/Widget;
 }
@@ -1121,9 +1069,6 @@ public abstract interface class com/github/ajalt/mordant/terminal/CursorMovement
 	public abstract fun up (I)V
 }
 
-public abstract interface annotation class com/github/ajalt/mordant/terminal/ExperimentalTerminalApi : java/lang/annotation/Annotation {
-}
-
 public final class com/github/ajalt/mordant/terminal/HtmlRendererKt {
 	public static final fun outputAsHtml (Lcom/github/ajalt/mordant/terminal/TerminalRecorder;ZZLcom/github/ajalt/colormath/Color;)Ljava/lang/String;
 	public static synthetic fun outputAsHtml$default (Lcom/github/ajalt/mordant/terminal/TerminalRecorder;ZZLcom/github/ajalt/colormath/Color;ILjava/lang/Object;)Ljava/lang/String;
@@ -1167,6 +1112,13 @@ public abstract class com/github/ajalt/mordant/terminal/Prompt {
 	protected fun renderValue (Ljava/lang/Object;)Ljava/lang/String;
 }
 
+public final class com/github/ajalt/mordant/terminal/PromptKt {
+	public static final fun prompt (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/String;Ljava/lang/Object;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+	public static final fun prompt (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/String;Ljava/lang/String;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+	public static synthetic fun prompt$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/String;Ljava/lang/Object;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object;
+	public static synthetic fun prompt$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/String;Ljava/lang/String;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;
+}
+
 public abstract class com/github/ajalt/mordant/terminal/StandardTerminalInterface : com/github/ajalt/mordant/terminal/TerminalInterface {
 	public fun <init> ()V
 	public fun completePrintRequest (Lcom/github/ajalt/mordant/terminal/PrintRequest;)V
@@ -1188,19 +1140,12 @@ public final class com/github/ajalt/mordant/terminal/StringPrompt : com/github/a
 public final class com/github/ajalt/mordant/terminal/Terminal {
 	public fun <init> (Lcom/github/ajalt/mordant/rendering/AnsiLevel;Lcom/github/ajalt/mordant/rendering/Theme;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Boolean;ILjava/lang/Boolean;Lcom/github/ajalt/mordant/terminal/TerminalInterface;)V
 	public synthetic fun <init> (Lcom/github/ajalt/mordant/rendering/AnsiLevel;Lcom/github/ajalt/mordant/rendering/Theme;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Boolean;ILjava/lang/Boolean;Lcom/github/ajalt/mordant/terminal/TerminalInterface;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
-	public final fun danger (Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
-	public static synthetic fun danger$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
-	public final fun getColors ()Lcom/github/ajalt/mordant/terminal/TerminalColors;
 	public final fun getCursor ()Lcom/github/ajalt/mordant/terminal/TerminalCursor;
-	public final fun getInfo ()Lcom/github/ajalt/mordant/terminal/TerminalInfo;
 	public final fun getSize ()Lcom/github/ajalt/mordant/rendering/Size;
 	public final fun getTabWidth ()I
+	public final fun getTerminalInfo ()Lcom/github/ajalt/mordant/terminal/TerminalInfo;
 	public final fun getTerminalInterface ()Lcom/github/ajalt/mordant/terminal/TerminalInterface;
 	public final fun getTheme ()Lcom/github/ajalt/mordant/rendering/Theme;
-	public final fun info (Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
-	public static synthetic fun info$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
-	public final fun muted (Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
-	public static synthetic fun muted$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
 	public final fun print (Lcom/github/ajalt/mordant/rendering/Widget;Z)V
 	public final fun print (Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
 	public static synthetic fun print$default (Lcom/github/ajalt/mordant/terminal/Terminal;Lcom/github/ajalt/mordant/rendering/Widget;ZILjava/lang/Object;)V
@@ -1211,61 +1156,13 @@ public final class com/github/ajalt/mordant/terminal/Terminal {
 	public static synthetic fun println$default (Lcom/github/ajalt/mordant/terminal/Terminal;Lcom/github/ajalt/mordant/rendering/Widget;ZILjava/lang/Object;)V
 	public static synthetic fun println$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
 	public static synthetic fun println$default (Lcom/github/ajalt/mordant/terminal/Terminal;ZILjava/lang/Object;)V
-	public final fun prompt (Ljava/lang/String;Ljava/lang/Object;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
-	public final fun prompt (Ljava/lang/String;Ljava/lang/String;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-	public static synthetic fun prompt$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/String;Ljava/lang/Object;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object;
-	public static synthetic fun prompt$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/String;Ljava/lang/String;ZZZLjava/util/Collection;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;
 	public final fun rawPrint (Ljava/lang/String;Z)V
 	public static synthetic fun rawPrint$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/String;ZILjava/lang/Object;)V
 	public final fun readLineOrNull (Z)Ljava/lang/String;
 	public final fun render (Lcom/github/ajalt/mordant/rendering/Widget;)Ljava/lang/String;
 	public final fun render (Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;)Ljava/lang/String;
 	public static synthetic fun render$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ILjava/lang/Object;)Ljava/lang/String;
-	public final fun success (Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
-	public static synthetic fun success$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
 	public final fun updateSize ()Lcom/github/ajalt/mordant/rendering/Size;
-	public final fun warning (Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
-	public static synthetic fun warning$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
-}
-
-public final class com/github/ajalt/mordant/terminal/TerminalColors {
-	public final fun cmyk (IIII)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun color (Lcom/github/ajalt/colormath/Color;)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBlack ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBlue ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBold ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBrightBlue ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBrightCyan ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBrightGreen ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBrightMagenta ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBrightRed ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBrightWhite ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getBrightYellow ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getCyan ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getDanger ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getDim ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getGray ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getGreen ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getInfo ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getInverse ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getItalic ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getMagenta ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getMuted ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getPlain ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getRed ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getStrikethrough ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getSuccess ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getUnderline ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getWarning ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getWhite ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun getYellow ()Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun gray (Ljava/lang/Number;)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun hsl (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun hsv (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun lab (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun rgb (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun rgb (Ljava/lang/String;)Lcom/github/ajalt/mordant/rendering/TextStyle;
-	public final fun xyz (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/github/ajalt/mordant/rendering/TextStyle;
 }
 
 public abstract interface class com/github/ajalt/mordant/terminal/TerminalCursor {
@@ -1284,6 +1181,19 @@ public final class com/github/ajalt/mordant/terminal/TerminalDetection {
 	public final fun detectTerminal (Lcom/github/ajalt/mordant/rendering/AnsiLevel;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;ZZ)Lcom/github/ajalt/mordant/terminal/TerminalInfo;
 }
 
+public final class com/github/ajalt/mordant/terminal/TerminalExtensionsKt {
+	public static final fun danger (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
+	public static synthetic fun danger$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
+	public static final fun info (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
+	public static synthetic fun info$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
+	public static final fun muted (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
+	public static synthetic fun muted$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
+	public static final fun success (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
+	public static synthetic fun success$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
+	public static final fun warning (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;Z)V
+	public static synthetic fun warning$default (Lcom/github/ajalt/mordant/terminal/Terminal;Ljava/lang/Object;Lcom/github/ajalt/mordant/rendering/Whitespace;Lcom/github/ajalt/mordant/rendering/TextAlign;Lcom/github/ajalt/mordant/rendering/OverflowWrap;Ljava/lang/Integer;ZILjava/lang/Object;)V
+}
+
 public final class com/github/ajalt/mordant/terminal/TerminalInfo {
 	public fun <init> (Lcom/github/ajalt/mordant/rendering/AnsiLevel;ZZZZ)V
 	public final fun component1 ()Lcom/github/ajalt/mordant/rendering/AnsiLevel;
@@ -1296,10 +1206,10 @@ public final class com/github/ajalt/mordant/terminal/TerminalInfo {
 	public fun equals (Ljava/lang/Object;)Z
 	public final fun getAnsiHyperLinks ()Z
 	public final fun getAnsiLevel ()Lcom/github/ajalt/mordant/rendering/AnsiLevel;
-	public final fun getCrClearsLine ()Z
 	public final fun getInputInteractive ()Z
 	public final fun getInteractive ()Z
 	public final fun getOutputInteractive ()Z
+	public final fun getSupportsAnsiCursor ()Z
 	public fun hashCode ()I
 	public final fun setAnsiHyperLinks (Z)V
 	public final fun setAnsiLevel (Lcom/github/ajalt/mordant/rendering/AnsiLevel;)V
@@ -1654,32 +1564,6 @@ public final class com/github/ajalt/mordant/widgets/ProgressBar : com/github/aja
 	public fun render (Lcom/github/ajalt/mordant/terminal/Terminal;I)Lcom/github/ajalt/mordant/rendering/Lines;
 }
 
-public class com/github/ajalt/mordant/widgets/ProgressBuilder {
-	public final fun completed (Ljava/lang/String;ZLcom/github/ajalt/mordant/rendering/TextStyle;)V
-	public static synthetic fun completed$default (Lcom/github/ajalt/mordant/widgets/ProgressBuilder;Ljava/lang/String;ZLcom/github/ajalt/mordant/rendering/TextStyle;ILjava/lang/Object;)V
-	public final fun getPadding ()I
-	public final fun percentage ()V
-	public final fun progressBar (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Ljava/lang/Boolean;)V
-	public static synthetic fun progressBar$default (Lcom/github/ajalt/mordant/widgets/ProgressBuilder;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Ljava/lang/Boolean;ILjava/lang/Object;)V
-	public final fun setPadding (I)V
-	public final fun speed (Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/TextStyle;)V
-	public static synthetic fun speed$default (Lcom/github/ajalt/mordant/widgets/ProgressBuilder;Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/TextStyle;ILjava/lang/Object;)V
-	public final fun spinner (Lcom/github/ajalt/mordant/widgets/Spinner;I)V
-	public static synthetic fun spinner$default (Lcom/github/ajalt/mordant/widgets/ProgressBuilder;Lcom/github/ajalt/mordant/widgets/Spinner;IILjava/lang/Object;)V
-	public final fun text (Ljava/lang/String;)V
-	public final fun timeRemaining (Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/TextStyle;)V
-	public static synthetic fun timeRemaining$default (Lcom/github/ajalt/mordant/widgets/ProgressBuilder;Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/TextStyle;ILjava/lang/Object;)V
-}
-
-public final class com/github/ajalt/mordant/widgets/ProgressLayout {
-	public final fun build (JLjava/lang/Long;DLjava/lang/Double;)Lcom/github/ajalt/mordant/rendering/Widget;
-	public static synthetic fun build$default (Lcom/github/ajalt/mordant/widgets/ProgressLayout;JLjava/lang/Long;DLjava/lang/Double;ILjava/lang/Object;)Lcom/github/ajalt/mordant/rendering/Widget;
-}
-
-public final class com/github/ajalt/mordant/widgets/ProgressLayoutKt {
-	public static final fun progressLayout (Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/mordant/widgets/ProgressLayout;
-}
-
 public final class com/github/ajalt/mordant/widgets/SelectList : com/github/ajalt/mordant/rendering/Widget {
 	public fun <init> (Ljava/util/List;Lcom/github/ajalt/mordant/rendering/Widget;IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/Widget;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;)V
 	public synthetic fun <init> (Ljava/util/List;Lcom/github/ajalt/mordant/rendering/Widget;IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/github/ajalt/mordant/rendering/Widget;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;Lcom/github/ajalt/mordant/rendering/TextStyle;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/animation/Animation.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/animation/Animation.kt
index f6a131f0..b3901c81 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/animation/Animation.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/animation/Animation.kt
@@ -30,8 +30,6 @@ import com.github.ajalt.mordant.widgets.progress.progressBarLayout
  * cause garbled output, so usage of this class should be serialized.
  */
 abstract class Animation<T>(
-    @Deprecated("This parameter is ignored; animations never print a trailing linebreak.")
-    private val trailingLinebreak: Boolean = true,
     val terminal: Terminal,
 ) : StoppableAnimation {
     private data class State(
@@ -150,7 +148,7 @@ abstract class Animation<T>(
                 text = terminal.render(rendered)
             )
         }
-        if (!old.interceptorInstalled && terminal.info.outputInteractive) {
+        if (!old.interceptorInstalled && terminal.terminalInfo.outputInteractive) {
             terminal.addInterceptor(interceptor)
         }
         // Print an empty widget to trigger our interceptor, which will add the rendered text
@@ -171,7 +169,7 @@ abstract class Animation<T>(
             startOfLine()
             if (CR_IMPLIES_LF) up(1)
 
-            if (terminal.info.crClearsLine) {
+            if (terminal.terminalInfo.supportsAnsiCursor) {
                 // IntelliJ doesn't support cursor moves, so this is all we can do
                 return@getMoves
             }
@@ -208,10 +206,9 @@ abstract class Animation<T>(
  * @see Animation
  */
 inline fun <T> Terminal.animation(
-    trailingLinebreak: Boolean = true,
     crossinline draw: (T) -> Widget,
 ): Animation<T> {
-    return object : Animation<T>(trailingLinebreak, this) {
+    return object : Animation<T>(this) {
         override fun renderData(data: T): Widget = draw(data)
     }
 }
@@ -226,10 +223,9 @@ inline fun <T> Terminal.textAnimation(
     overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
     width: Int? = null,
     tabWidth: Int? = null,
-    trailingLinebreak: Boolean = true,
     crossinline draw: (T) -> String,
 ): Animation<T> {
-    return object : Animation<T>(trailingLinebreak, this) {
+    return object : Animation<T>(this) {
         override fun renderData(data: T): Widget {
             return Text(draw(data), whitespace, align, overflowWrap, width, tabWidth)
         }
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/input/RawMode.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/input/RawMode.kt
index d9ab4fc8..fb378089 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/input/RawMode.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/input/RawMode.kt
@@ -13,7 +13,7 @@ import kotlin.time.TimeSource
  * @throws RuntimeException if the terminal is not interactive or raw mode cannot be entered.
  */
 fun Terminal.enterRawMode(mouseTracking: MouseTracking = MouseTracking.Off): RawModeScope {
-    if (!info.inputInteractive) {
+    if (!terminalInfo.inputInteractive) {
         throw IllegalStateException("Cannot enter raw mode on a non-interactive terminal")
     }
     return RawModeScope(this, terminalInterface.enterRawMode(mouseTracking), mouseTracking)
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Borders.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Borders.kt
index 59194c09..489662e6 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Borders.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Borders.kt
@@ -22,8 +22,4 @@ enum class Borders(
     LEFT_TOP_BOTTOM(left = true, top = true, right = false, bottom = true),
     LEFT_TOP_RIGHT(left = true, top = true, right = true, bottom = false),
     ALL(left = true, top = true, right = true, bottom = true),
-
-    @Suppress("unused")
-    @Deprecated("Use TOP_BOTTOM", replaceWith = ReplaceWith("TOP_BOTTOM"))
-    TOM_BOTTOM(left = false, top = true, right = false, bottom = true),
 }
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Table.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Table.kt
index 17ec89c1..a5ed67d6 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Table.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/Table.kt
@@ -74,7 +74,7 @@ internal class TableImpl(
     val borderStyle: TextStyle,
     val headerRowCount: Int,
     val footerRowCount: Int,
-    val columnWidths: List<ColumnWidth.Custom>,
+    val columnWidths: List<ColumnWidth>,
     val tableBorders: Borders?,
     val addPaddingWidthToFixedWidth: Boolean,
 ) : Table() {
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDsl.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDsl.kt
index b39fd49a..89f1c109 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDsl.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDsl.kt
@@ -2,6 +2,9 @@ package com.github.ajalt.mordant.table
 
 import com.github.ajalt.colormath.Color
 import com.github.ajalt.mordant.rendering.*
+import com.github.ajalt.mordant.table.ColumnWidth.Companion.Auto
+import com.github.ajalt.mordant.table.ColumnWidth.Companion.Expand
+import com.github.ajalt.mordant.table.ColumnWidth.Companion.Fixed
 import com.github.ajalt.mordant.widgets.Caption
 import com.github.ajalt.mordant.widgets.Padding
 import com.github.ajalt.mordant.widgets.withPadding
@@ -38,9 +41,6 @@ interface CellStyleBuilderBase {
 }
 
 interface CellStyleBuilder : CellStyleBuilderBase {
-    @Deprecated("borders has been renamed to cellBorders", replaceWith = ReplaceWith("cellBorders"))
-    var borders: Borders?
-
     /**
      * Borders around each individual cell.
      *
@@ -73,81 +73,80 @@ interface CellStyleBuilder : CellStyleBuilderBase {
     }
 }
 
-sealed class ColumnWidth {
-    // TODO(3.0): this is a separate class for backwards compatibility; make other ColumnWidth subclasses
-    //  instances of this in 3.0
+/**
+ * Configuration for how a column should be sized in a table.
+ */
+data class ColumnWidth(
     // TODO(3.0): add a `minimumWidth?` field and use it for progress cells like timeRemaining
     /**
-     * A column width with custom behavior.
+     * The priority of the column when allocating available width.
+     *
+     * Available width is allocated to columns in decreasing order of priority.
+     *
+     * - [Fixed] columns have a priority of 3.
+     * - [Auto] columns have a priority of 2.
+     * - [Expand] columns have a priority of 1.
      */
-    data class Custom(
-        /** The fixed width of the column, or `null` if the width should be computed automatically */
-        val width: Int?,
-        /**
-         * The weight of the column when expanding, or `null` if the column should not expand.
-         *
-         * If there are multiple expanding columns with the same [priority], the available width
-         * will be divided among them proportional to their weights.
-         */
-        val expandWeight: Float?,
-        /**
-         * The priority of the column when allocating available width.
-         *
-         * Available width is allocated to columns in decreasing order of priority.
-         *
-         * - [Fixed] columns have a priority of 3.
-         * - [Auto] columns have a priority of 2.
-         * - [Expand] columns have a priority of 1.
-         */
-        val priority: Int,
-    ) : ColumnWidth() {
-        init {
-            require(width == null || width > 0) { "width must be greater than zero" }
-            require(expandWeight == null || expandWeight > 0f) {
-                "expandWeight must be greater than zero"
-            }
-            require(width == null || expandWeight == null) {
-                "Cannot set both width and expandWeight"
-            }
+    val priority: Int,
+    /**
+     * The fixed width of the column, or `null` if the width should be computed automatically
+     */
+    val width: Int? = null,
+    /**
+     * The weight of the column when expanding, or `null` if the column should not expand.
+     *
+     * If there are multiple expanding columns with the same [priority], the available width
+     * will be divided among them proportional to their weights.
+     */
+    val expandWeight: Float? = null,
+) {
+    init {
+        require(width == null || width > 0) { "width must be greater than zero" }
+        require(expandWeight == null || expandWeight > 0f) {
+            "expandWeight must be greater than zero"
+        }
+        require(width == null || expandWeight == null) {
+            "Cannot set both width and expandWeight"
         }
+    }
 
-        override fun toString(): String {
-            return when {
-                isAuto -> "Auto"
-                isExpand -> "Expand($expandWeight)"
-                isFixed -> "Fixed($width)"
-                else -> "Custom(width=$width, expandWeight=$expandWeight, priority=$priority)"
-            }
+    override fun toString(): String {
+        return when {
+            isAuto -> "Auto"
+            isExpand -> "Expand($expandWeight)"
+            isFixed -> "Fixed($width)"
+            else -> "Custom(width=$width, expandWeight=$expandWeight, priority=$priority)"
         }
     }
 
-    /** The column will fit to the size of its content */
-    data object Auto : ColumnWidth()
+    @Suppress("FunctionName")
+    companion object {
 
-    /**
-     * The column will have a fixed [width].
-     *
-     * The width includes padding, so increasing horizontal padding of a fixed column will decrease content width rather
-     * than expand the column.
-     */
-    class Fixed(val width: Int) : ColumnWidth() {
-        init {
+        /** The column will fit to the size of its content */
+        val Auto = ColumnWidth(2)
+
+        /**
+         * The column will have a fixed [width].
+         *
+         * The width includes padding, so increasing horizontal padding of a fixed column will decrease content width rather
+         * than expand the column.
+         */
+        fun Fixed(width: Int): ColumnWidth {
             require(width > 0) { "width must be greater than zero" }
+            return ColumnWidth(3, width)
         }
-    }
 
-    /**
-     * The column will expand to fill the available terminal width.
-     *
-     * If there are multiple expanding columns, the available width will be divided among them
-     * proportional to their [weight]s.
-     */
-    class Expand(val weight: Float = 1f) : ColumnWidth() {
-        init {
-            require(weight > 0) { "weight must be greater than zero" }
+        /**
+         * The column will expand to fill the available terminal width.
+         *
+         * If there are multiple expanding columns, the available width will be divided among them
+         * proportional to their [weight]s.
+         */
+        fun Expand(weight: Number = 1f): ColumnWidth {
+            val w = weight.toFloat()
+            require(w > 0) { "weight must be greater than zero" }
+            return ColumnWidth(1, null, w)
         }
-
-        constructor(weight: Number) : this(weight.toFloat())
     }
 }
 
@@ -211,9 +210,6 @@ interface TableBuilder : CellStyleBuilder, ColumnHolderBuilder {
 
     /** Configure the footer section. */
     fun footer(init: SectionBuilder.() -> Unit)
-
-    @Deprecated("`outerBorder=false` has been replaced with `tableBorders=Borders.NONE`")
-    var outerBorder: Boolean
 }
 
 @MordantDsl
@@ -375,47 +371,11 @@ fun verticalLayout(init: VerticalLayoutBuilder.() -> Unit): Widget {
     return VerticalLayoutBuilderInstance().apply(init).build()
 }
 
-@Deprecated(
-    "row is renamed to horizontalLayout",
-    replaceWith = ReplaceWith("horizontalLayout(init)")
-)
-fun row(padding: Int = 0, init: HorizontalLayoutBuilder.() -> Unit): Widget {
-    return horizontalLayout {
-        spacing = padding
-        init()
-    }
-}
-
-@Deprecated(
-    "column is renamed to verticalLayout",
-    replaceWith = ReplaceWith("verticalLayout(init)")
-)
-fun column(padding: Int = 0, init: VerticalLayoutBuilder.() -> Unit): Widget = verticalLayout {
-    init()
-    this.spacing = padding
-}
-
-internal fun ColumnWidth?.toCustom(): ColumnWidth.Custom {
-    return when (this) {
-        is ColumnWidth.Expand -> ColumnWidth.Custom(null, weight, 1)
-        null, is ColumnWidth.Auto -> ColumnWidth.Custom(null, null, 2)
-        is ColumnWidth.Fixed -> ColumnWidth.Custom(width, null, 3)
-        is ColumnWidth.Custom -> this
-    }
-}
-
 internal val ColumnWidth.isAuto: Boolean
-    get() {
-        return this is ColumnWidth.Auto ||
-                this is ColumnWidth.Custom && this.width == null && this.expandWeight == null
-    }
+    get() = this.width == null && this.expandWeight == null
 
 internal val ColumnWidth.isExpand: Boolean
-    get() {
-        return this is ColumnWidth.Expand || this is ColumnWidth.Custom && this.expandWeight != null
-    }
+    get() = this.expandWeight != null
 
 internal val ColumnWidth.isFixed: Boolean
-    get() {
-        return this is ColumnWidth.Fixed || this is ColumnWidth.Custom && this.width != null
-    }
+    get() = this.width != null
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDslInstances.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDslInstances.kt
index 2de2baf6..29bbab1a 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDslInstances.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableDslInstances.kt
@@ -14,13 +14,6 @@ private class CellStyleBuilderMixin : CellStyleBuilder {
     override var align: TextAlign? = null
     override var verticalAlign: VerticalAlign? = null
     override var overflowWrap: OverflowWrap? = null
-
-    @Deprecated("borders has been renamed to cellBorders", replaceWith = ReplaceWith("cellBorders"))
-    override var borders: Borders?
-        get() = cellBorders
-        set(value) {
-            cellBorders = value
-        }
 }
 
 
@@ -44,13 +37,6 @@ internal class TableBuilderInstance : TableBuilder, CellStyleBuilder by CellStyl
     var captionBottom: Widget? = null
         private set
 
-    @Deprecated("`outerBorder=false` has been replaced with `tableBorders=Borders.NONE`")
-    override var outerBorder: Boolean
-        get() = tableBorders != Borders.ALL
-        set(value) {
-            tableBorders = if (value) Borders.ALL else Borders.NONE
-        }
-
     override fun captionTop(widget: Widget) {
         captionTop = widget
     }
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableLayout.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableLayout.kt
index bd22bff4..bcff8daa 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableLayout.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/TableLayout.kt
@@ -1,6 +1,7 @@
 package com.github.ajalt.mordant.table
 
 import com.github.ajalt.mordant.rendering.*
+import com.github.ajalt.mordant.table.ColumnWidth.Companion.Auto
 import com.github.ajalt.mordant.widgets.EmptyWidget
 import com.github.ajalt.mordant.widgets.Padding
 import com.github.ajalt.mordant.widgets.Text
@@ -43,7 +44,7 @@ internal class TableLayout(private val table: TableBuilderInstance) {
         val columnCount = rows.maxOf { it.size }
 
         val columnWidths = List(columnCount) { i ->
-            table.columns[i]?.width.toCustom()
+            table.columns[i]?.width ?: Auto
         }
         return TableImpl(
             rows = rows,
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/VerticalLayout.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/VerticalLayout.kt
index 6a159ea8..8699210b 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/VerticalLayout.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/table/VerticalLayout.kt
@@ -4,6 +4,7 @@ import com.github.ajalt.mordant.internal.DEFAULT_STYLE
 import com.github.ajalt.mordant.internal.EMPTY_LINE
 import com.github.ajalt.mordant.rendering.*
 import com.github.ajalt.mordant.rendering.TextAlign.NONE
+import com.github.ajalt.mordant.table.ColumnWidth.Companion.Auto
 import com.github.ajalt.mordant.terminal.Terminal
 
 private class VerticalLayoutCell(
@@ -55,7 +56,7 @@ internal class VerticalLayout private constructor(
 
     override fun render(t: Terminal, width: Int): Lines {
         val renderWidth = when {
-            columnWidth is ColumnWidth.Expand -> width
+            columnWidth.isExpand -> width
             hasAlignedCells -> measure(t, width).max
             else -> width
         }.coerceAtMost(width)
@@ -68,7 +69,7 @@ internal class VerticalLayout private constructor(
             if (i > 0) repeat(spacing) { lines += spacingLine }
             var rendered = cell.content.render(t, renderWidth).withStyle(cell.style)
 
-            val w = columnWidth.toCustom()
+            val w = columnWidth
             rendered = when {
                 w.expandWeight != null -> rendered.setSize(width, textAlign = cell.textAlign)
                 w.width != null -> rendered.setSize(w.width, textAlign = cell.textAlign)
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/ExperimentalTerminalApi.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/ExperimentalTerminalApi.kt
deleted file mode 100644
index cc2c2a93..00000000
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/ExperimentalTerminalApi.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.github.ajalt.mordant.terminal
-
-@Deprecated("This Annotation is no longer necessary")
-@RequiresOptIn
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
-annotation class ExperimentalTerminalApi
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Prompt.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Prompt.kt
index 14f47d2d..749724e9 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Prompt.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Prompt.kt
@@ -335,3 +335,67 @@ class ConfirmationPrompt<T : Any>(
         }
     }
 }
+
+
+/**
+ * Print a [prompt] to the user and return the value they enter.
+ *
+ * To customize the prompt behavior, see the [Prompt] class.
+ *
+ * @param prompt The message asking for input to show the user
+ * @param default The value to return if the user enters an empty line, or `null` to require a value
+ * @param showDefault If true and a [default] is specified, add the default value to the prompt
+ * @param hideInput If true, the user's input will be treated like a password and hidden from
+ *   the screen. This value will be ignored on platforms where it is not supported.
+ * @param choices The set of values that the user must choose from.
+ * @param promptSuffix A string to append after [prompt] when showing the user the prompt
+ * @param invalidChoiceMessage The message to show the user if [choices] is specified,
+ *   and they enter a value that isn't one of the choices.
+ */
+fun Terminal.prompt(
+    prompt: String,
+    default: String? = null,
+    showDefault: Boolean = true,
+    showChoices: Boolean = true,
+    hideInput: Boolean = false,
+    choices: Collection<String> = emptyList(),
+    promptSuffix: String = ": ",
+    invalidChoiceMessage: String = "Invalid value, choose from ",
+): String? = prompt(
+    prompt,
+    default,
+    showDefault,
+    showChoices,
+    hideInput,
+    choices,
+    promptSuffix,
+    invalidChoiceMessage
+) { ConversionResult.Valid(it) }
+
+inline fun <T> Terminal.prompt(
+    prompt: String,
+    default: T? = null,
+    showDefault: Boolean = true,
+    showChoices: Boolean = true,
+    hideInput: Boolean = false,
+    choices: Collection<T> = emptyList(),
+    promptSuffix: String = ": ",
+    invalidChoiceMessage: String = "Invalid value, choose from ",
+    crossinline convert: (String) -> ConversionResult<T>,
+): T? {
+    return object : Prompt<T>(
+        prompt = prompt,
+        terminal = this,
+        default = default,
+        showDefault = showDefault,
+        showChoices = showChoices,
+        hideInput = hideInput,
+        choices = choices,
+        promptSuffix = promptSuffix,
+        invalidChoiceMessage = invalidChoiceMessage,
+    ) {
+        override fun convert(input: String): ConversionResult<T> {
+            return convert(input)
+        }
+    }.ask()
+}
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Terminal.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Terminal.kt
index 02ac9a6f..798887df 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Terminal.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/Terminal.kt
@@ -29,7 +29,7 @@ class Terminal private constructor(
     private val nonInteractiveWidth: Int?,
     private val nonInteractiveHeight: Int?,
     /** The terminal capabilities that were detected or set in the constructor. */
-    val info: TerminalInfo,
+    val terminalInfo: TerminalInfo,
 ) {
 
     /**
@@ -65,7 +65,7 @@ class Terminal private constructor(
         forceHeight = height,
         nonInteractiveWidth = nonInteractiveWidth,
         nonInteractiveHeight = nonInteractiveHeight,
-        info = terminalInterface.info(
+        terminalInfo = terminalInterface.info(
             ansiLevel = ansiLevel,
             hyperlinks = hyperlinks,
             outputInteractive = interactive,
@@ -79,7 +79,7 @@ class Terminal private constructor(
     private val atomicSize: MppAtomicRef<Size> =
         MppAtomicRef(
             terminalInterface.detectSize(
-                info,
+                terminalInfo,
                 forceWidth,
                 forceHeight,
                 nonInteractiveWidth,
@@ -103,7 +103,7 @@ class Terminal private constructor(
     fun updateSize(): Size {
         return atomicSize.update {
             terminalInterface.detectSize(
-                info,
+                terminalInfo,
                 forceWidth,
                 forceHeight,
                 nonInteractiveWidth,
@@ -112,102 +112,21 @@ class Terminal private constructor(
         }.second
     }
 
-    /**
-     * Colors and styles that are downsampled based on the current terminal [info].
-     *
-     * This can be used if you want to style a string that is going to be printed with
-     * [kotlin.io.print]. If you're using the terminal's [print], you can use [TextColors] and
-     * [TextStyles] directly instead.
-     */
-    @Deprecated("Use TextColors or .theme instead") // TODO(3.0) remove
-    val colors: TerminalColors = TerminalColors(info, theme)
-
     /**
      * Functions for controlling the terminal's cursor.
      *
      * If the terminal is not interactive, all the cursor functions are no-ops.
      */
     val cursor: TerminalCursor = when {
-        info.interactive -> makePrintingTerminalCursor(this)
+        terminalInfo.interactive -> makePrintingTerminalCursor(this)
         else -> DisabledTerminalCursor
     }
 
-    /**
-     * Print a line styled with the theme's [success][Theme.success] style.
-     */
-    fun success(
-        // TODO(3.0): make extensions
-        message: Any?,
-        whitespace: Whitespace = Whitespace.PRE,
-        align: TextAlign = TextAlign.NONE,
-        overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
-        width: Int? = null,
-        stderr: Boolean = false,
-    ) {
-        println(theme.success(message.toString()), whitespace, align, overflowWrap, width, stderr)
-    }
-
-    /**
-     * Print a line styled with the theme's [danger][Theme.danger] style.
-     */
-    fun danger(
-        message: Any?,
-        whitespace: Whitespace = Whitespace.PRE,
-        align: TextAlign = TextAlign.NONE,
-        overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
-        width: Int? = null,
-        stderr: Boolean = false,
-    ) {
-        println(theme.danger(message.toString()), whitespace, align, overflowWrap, width, stderr)
-    }
-
-    /**
-     * Print a line styled with the theme's [warning][Theme.warning] style.
-     */
-    fun warning(
-        message: Any?,
-        whitespace: Whitespace = Whitespace.PRE,
-        align: TextAlign = TextAlign.NONE,
-        overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
-        width: Int? = null,
-        stderr: Boolean = false,
-    ) {
-        println(theme.warning(message.toString()), whitespace, align, overflowWrap, width, stderr)
-    }
-
-    /**
-     * Print a line styled with the theme's [info][Theme.info] style.
-     */
-    fun info(
-        message: Any?,
-        whitespace: Whitespace = Whitespace.PRE,
-        align: TextAlign = TextAlign.NONE,
-        overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
-        width: Int? = null,
-        stderr: Boolean = false,
-    ) {
-        println(theme.info(message.toString()), whitespace, align, overflowWrap, width, stderr)
-    }
-
-    /**
-     * Print a line styled with the theme's [muted][Theme.muted] style.
-     */
-    fun muted(
-        message: Any?,
-        whitespace: Whitespace = Whitespace.PRE,
-        align: TextAlign = TextAlign.NONE,
-        overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
-        width: Int? = null,
-        stderr: Boolean = false,
-    ) {
-        println(theme.muted(message.toString()), whitespace, align, overflowWrap, width, stderr)
-    }
-
     /**
      * Print a [message] to the terminal.
      *
      * Any contained [TextColors] and [TextStyles] will be automatically downsampled based on the
-     * current terminal's [info].
+     * current terminal's [terminalInfo].
      *
      * @param message The message to print as a string.
      * @param whitespace How to handle whitespace and line wrapping. By default, whitespace is
@@ -233,7 +152,7 @@ class Terminal private constructor(
      * Print a [message] to the terminal, followed by a line break.
      *
      * Any contained [TextColors] and [TextStyles] will be automatically downsampled based on the
-     * current terminal's [info].
+     * current terminal's [terminalInfo].
      *
      * @param message The message to print as a string.
      * @param whitespace How to handle whitespace and line wrapping. By default, whitespace is
@@ -281,7 +200,7 @@ class Terminal private constructor(
      * Render a [message] to a string.
      *
      * Any contained [TextColors] and [TextStyles] will be automatically downsampled based on the
-     * current terminal's [info].
+     * current terminal's [terminalInfo].
      *
      * @param message The message to render as a string.
      * @param whitespace How to handle whitespace and line wrapping. By default, whitespace is
@@ -299,7 +218,7 @@ class Terminal private constructor(
         width: Int? = null,
     ): String {
         return when (message) {
-            is Lines -> renderLinesAnsi(message, info.ansiLevel, info.ansiHyperLinks)
+            is Lines -> renderLinesAnsi(message, terminalInfo.ansiLevel, terminalInfo.ansiHyperLinks)
             is Widget -> render(message)
             else -> render(Text(message.toString(), whitespace, align, overflowWrap, width))
         }
@@ -307,7 +226,7 @@ class Terminal private constructor(
 
     /** Render a [widget] as a string */
     fun render(widget: Widget): String {
-        return renderLinesAnsi(widget.render(this), info.ansiLevel, info.ansiHyperLinks)
+        return renderLinesAnsi(widget.render(this), terminalInfo.ansiLevel, terminalInfo.ansiHyperLinks)
     }
 
     /**
@@ -320,69 +239,6 @@ class Terminal private constructor(
         return terminalInterface.readLineOrNull(hideInput)
     }
 
-    inline fun <T> prompt(
-        prompt: String,
-        default: T? = null,
-        showDefault: Boolean = true,
-        showChoices: Boolean = true,
-        hideInput: Boolean = false,
-        choices: Collection<T> = emptyList(),
-        promptSuffix: String = ": ",
-        invalidChoiceMessage: String = "Invalid value, choose from ",
-        crossinline convert: (String) -> ConversionResult<T>,
-    ): T? {
-        return object : Prompt<T>(
-            prompt = prompt,
-            terminal = this,
-            default = default,
-            showDefault = showDefault,
-            showChoices = showChoices,
-            hideInput = hideInput,
-            choices = choices,
-            promptSuffix = promptSuffix,
-            invalidChoiceMessage = invalidChoiceMessage,
-        ) {
-            override fun convert(input: String): ConversionResult<T> {
-                return convert(input)
-            }
-        }.ask()
-    }
-
-    /**
-     * Print a [prompt] to the user and return the value they enter.
-     *
-     * To customize the prompt behavior, see the [Prompt] class.
-     *
-     * @param prompt The message asking for input to show the user
-     * @param default The value to return if the user enters an empty line, or `null` to require a value
-     * @param showDefault If true and a [default] is specified, add the default value to the prompt
-     * @param hideInput If true, the user's input will be treated like a password and hidden from
-     *   the screen. This value will be ignored on platforms where it is not supported.
-     * @param choices The set of values that the user must choose from.
-     * @param promptSuffix A string to append after [prompt] when showing the user the prompt
-     * @param invalidChoiceMessage The message to show the user if [choices] is specified,
-     *   and they enter a value that isn't one of the choices.
-     */
-    fun prompt(
-        prompt: String,
-        default: String? = null,
-        showDefault: Boolean = true,
-        showChoices: Boolean = true,
-        hideInput: Boolean = false,
-        choices: Collection<String> = emptyList(),
-        promptSuffix: String = ": ",
-        invalidChoiceMessage: String = "Invalid value, choose from ",
-    ): String? = prompt(
-        prompt,
-        default,
-        showDefault,
-        showChoices,
-        hideInput,
-        choices,
-        promptSuffix,
-        invalidChoiceMessage
-    ) { ConversionResult.Valid(it) }
-
     /**
      * Print a [message] to the terminal without parsing or rendering it.
      *
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalColors.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalColors.kt
deleted file mode 100644
index 09cb7285..00000000
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalColors.kt
+++ /dev/null
@@ -1,177 +0,0 @@
-package com.github.ajalt.mordant.terminal
-
-import com.github.ajalt.colormath.Color
-import com.github.ajalt.mordant.internal.DEFAULT_STYLE
-import com.github.ajalt.mordant.internal.downsample
-import com.github.ajalt.mordant.rendering.TextColors
-import com.github.ajalt.mordant.rendering.TextStyle
-import com.github.ajalt.mordant.rendering.TextStyles
-import com.github.ajalt.mordant.rendering.Theme
-
-/**
- * TextStyles that are automatically downsampled to the level supported by the current terminal.
- *
- * Strings decorated with these styles will be downsampled correctly even if they are printed
- * directly rather than through [Terminal.print].
- */
-class TerminalColors internal constructor(
-    // TODO(3.0): remove
-    private val terminalInfo: TerminalInfo,
-    private val theme: Theme,
-) {
-    val black: TextStyle get() = downsample(TextColors.black)
-    val red: TextStyle get() = downsample(TextColors.red)
-    val green: TextStyle get() = downsample(TextColors.green)
-    val yellow: TextStyle get() = downsample(TextColors.yellow)
-    val blue: TextStyle get() = downsample(TextColors.blue)
-    val magenta: TextStyle get() = downsample(TextColors.magenta)
-    val cyan: TextStyle get() = downsample(TextColors.cyan)
-    val white: TextStyle get() = downsample(TextColors.white)
-    val gray: TextStyle get() = downsample(TextColors.gray)
-
-    val brightRed: TextStyle get() = downsample(TextColors.brightRed)
-    val brightGreen: TextStyle get() = downsample(TextColors.brightGreen)
-    val brightYellow: TextStyle get() = downsample(TextColors.brightYellow)
-    val brightBlue: TextStyle get() = downsample(TextColors.brightBlue)
-    val brightMagenta: TextStyle get() = downsample(TextColors.brightMagenta)
-    val brightCyan: TextStyle get() = downsample(TextColors.brightCyan)
-    val brightWhite: TextStyle get() = downsample(TextColors.brightWhite)
-
-    /** Render text with the [success][Theme.success] style from the current theme */
-    val success get(): TextStyle = downsample(theme.success)
-
-    /** Render text with the [danger][Theme.danger] style from the current theme */
-    val danger get(): TextStyle = downsample(theme.danger)
-
-    /** Render text with the [warning][Theme.warning] style from the current theme */
-    val warning get(): TextStyle = downsample(theme.warning)
-
-    /** Render text with the [info][Theme.info] style from the current theme */
-    val info get(): TextStyle = downsample(theme.info)
-
-    /** Render text with the [muted][Theme.muted] style from the current theme */
-    val muted: TextStyle get() = downsample(theme.muted)
-
-
-    /**
-     * Render text as bold or increased intensity.
-     *
-     * Might be rendered as a different color instead of a different font weight.
-     */
-    val bold: TextStyle get() = downsample(TextStyles.bold.style)
-
-    /**
-     * Render text as faint or decreased intensity.
-     *
-     * Not widely supported.
-     */
-    val dim: TextStyle get() = downsample(TextStyles.dim.style)
-
-    /**
-     * Render text as italic.
-     *
-     * Not widely supported, might be rendered as inverse instead of italic.
-     */
-    val italic: TextStyle get() = downsample(TextStyles.italic.style)
-
-    /**
-     * Underline text.
-     *
-     * Might be rendered with different colors instead of underline.
-     */
-    val underline: TextStyle get() = downsample(TextStyles.underline.style)
-
-    /** Render text with background and foreground colors switched. */
-    val inverse: TextStyle get() = downsample(TextStyles.inverse.style)
-
-    /**
-     * Render text with a strikethrough.
-     *
-     * Not widely supported.
-     */
-    val strikethrough: TextStyle get() = downsample(TextStyles.strikethrough.style)
-
-    /**
-     * No style.
-     */
-    val plain: TextStyle get() = DEFAULT_STYLE
-
-    /** @param hex An rgb hex string in the form "#ffffff" or "ffffff" */
-    fun rgb(hex: String): TextStyle = TextColors.rgb(hex, level)
-
-    /**
-     * Create a color code from an RGB color.
-     *
-     * @param r The red amount, in the range `[0, 1]`
-     * @param g The green amount, in the range `[0, 1]`
-     * @param b The blue amount, in the range `[0, 1]`
-     */
-    fun rgb(r: Number, g: Number, b: Number): TextStyle = TextColors.rgb(r, g, b, level)
-
-    /**
-     * Create a color code from an HSL color.
-     *
-     * @param h The hue, in the range `[0, 360]`
-     * @param s The saturation, in the range `[0, 1]`
-     * @param l The lightness, in the range `[0, 1]`
-     */
-    fun hsl(h: Number, s: Number, l: Number): TextStyle = TextColors.hsl(h, s, l, level)
-
-    /**
-     * Create a color code from an HSV color.
-     *
-     * @param h The hue, in the range `[0, 360]`
-     * @param s The saturation, in the range `[0, 1]`
-     * @param v The value, in the range `[0, 1]`
-     */
-    fun hsv(h: Number, s: Number, v: Number): TextStyle = TextColors.hsv(h, s, v, level)
-
-    /**
-     * Create a color code from a CMYK color.
-     *
-     * @param c The cyan amount, in the range `[0, 100]`
-     * @param m The magenta amount, in the range `[0, 100]`
-     * @param y The yellow amount, in the range `[0, 100]`
-     * @param k The black amount, in the range `[0, 100]`
-     */
-    fun cmyk(c: Int, m: Int, y: Int, k: Int): TextStyle = TextColors.cmyk(c, m, y, k, level)
-
-    /**
-     * Create a grayscale color code from a fraction in the range \[0, 1].
-     *
-     * @param fraction The fraction of white in the color. 0 is pure black, 1 is pure white.
-     */
-    fun gray(fraction: Number): TextStyle = TextColors.gray(fraction, level)
-
-    /**
-     * Create a color code from a CIE XYZ color.
-     *
-     * Conversions use D65 reference white, and sRGB profile.
-     *
-     * [x], [y], and [z] are generally in the interval `[0, 1]`
-     */
-    fun xyz(x: Number, y: Number, z: Number): TextStyle = TextColors.xyz(x, y, z, level)
-
-
-    /**
-     * Create a color code from a CIE LAB color.
-     *
-     * Conversions use D65 reference white, and sRGB profile.
-     *
-     * [l] is in the interval `[0, 100]`. [a] and [b] have unlimited range,
-     * but are generally in `[-100, 100]`
-     */
-    fun lab(l: Number, a: Number, b: Number): TextStyle = TextColors.lab(l, a, b, level)
-
-    /**
-     * Create a [TextStyle] with a foreground of [color], downsampled to a given [level].
-     *
-     * It's usually easier to use a function like [rgb] or [hsl] instead.
-     */
-    fun color(color: Color): TextStyle = TextColors.color(color, level)
-
-    private fun downsample(style: TextStyle): TextStyle =
-        downsample(style, level, terminalInfo.ansiHyperLinks)
-
-    private val level get() = terminalInfo.ansiLevel
-}
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalDetection.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalDetection.kt
index 186d69d9..2b99c1ce 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalDetection.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalDetection.kt
@@ -39,7 +39,7 @@ object TerminalDetection {
             ansiHyperLinks = ansiHyperLinks,
             outputInteractive = outputInteractive,
             inputInteractive = inputInteractive,
-            crClearsLine = ij // TODO(3.0): rename this to supportsAnsiCursor
+            supportsAnsiCursor = ij
         )
     }
 
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalExtensions.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalExtensions.kt
new file mode 100644
index 00000000..c8be5df7
--- /dev/null
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalExtensions.kt
@@ -0,0 +1,75 @@
+package com.github.ajalt.mordant.terminal
+
+import com.github.ajalt.mordant.rendering.OverflowWrap
+import com.github.ajalt.mordant.rendering.TextAlign
+import com.github.ajalt.mordant.rendering.Whitespace
+
+/**
+ * Print a line styled with the theme's [danger][Theme.danger] style.
+ */
+fun Terminal.danger(
+    message: Any?,
+    whitespace: Whitespace = Whitespace.PRE,
+    align: TextAlign = TextAlign.NONE,
+    overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
+    width: Int? = null,
+    stderr: Boolean = false,
+) {
+    println(theme.danger(message.toString()), whitespace, align, overflowWrap, width, stderr)
+}
+
+/**
+ * Print a line styled with the theme's [warning][Theme.warning] style.
+ */
+fun Terminal.warning(
+    message: Any?,
+    whitespace: Whitespace = Whitespace.PRE,
+    align: TextAlign = TextAlign.NONE,
+    overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
+    width: Int? = null,
+    stderr: Boolean = false,
+) {
+    println(theme.warning(message.toString()), whitespace, align, overflowWrap, width, stderr)
+}
+
+/**
+ * Print a line styled with the theme's [info][Theme.info] style.
+ */
+fun Terminal.info(
+    message: Any?,
+    whitespace: Whitespace = Whitespace.PRE,
+    align: TextAlign = TextAlign.NONE,
+    overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
+    width: Int? = null,
+    stderr: Boolean = false,
+) {
+    println(theme.info(message.toString()), whitespace, align, overflowWrap, width, stderr)
+}
+
+/**
+ * Print a line styled with the theme's [muted][Theme.muted] style.
+ */
+fun Terminal.muted(
+    message: Any?,
+    whitespace: Whitespace = Whitespace.PRE,
+    align: TextAlign = TextAlign.NONE,
+    overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
+    width: Int? = null,
+    stderr: Boolean = false,
+) {
+    println(theme.muted(message.toString()), whitespace, align, overflowWrap, width, stderr)
+}
+
+/**
+ * Print a line styled with the theme's [success][Theme.success] style.
+ */
+fun Terminal.success(
+    message: Any?,
+    whitespace: Whitespace = Whitespace.PRE,
+    align: TextAlign = TextAlign.NONE,
+    overflowWrap: OverflowWrap = OverflowWrap.NORMAL,
+    width: Int? = null,
+    stderr: Boolean = false,
+) {
+    println(theme.success(message.toString()), whitespace, align, overflowWrap, width, stderr)
+}
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalInfo.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalInfo.kt
index 70223436..5e1c3c1b 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalInfo.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalInfo.kt
@@ -25,7 +25,7 @@ data class TerminalInfo(
      * If true, `\r` will clear the entire line it's printed on in the current terminal, if false,
      * `\r` will only move the cursor
      */
-    val crClearsLine: Boolean,
+    val supportsAnsiCursor: Boolean,
 ) {
     /** Return true if both input and output are interactive */
     val interactive: Boolean get() = inputInteractive && outputInteractive
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalRecorder.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalRecorder.kt
index 93e98629..57e13a3e 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalRecorder.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/terminal/TerminalRecorder.kt
@@ -28,14 +28,14 @@ class TerminalRecorder private constructor(
         hyperlinks: Boolean = ansiLevel != AnsiLevel.NONE,
         outputInteractive: Boolean = ansiLevel != AnsiLevel.NONE,
         inputInteractive: Boolean = ansiLevel != AnsiLevel.NONE,
-        crClearsLine: Boolean = false, // TODO(3.0): rename this to supportsAnsiCursor
+        supportsAnsiCursor: Boolean = false,
     ) : this(
         TerminalInfo(
             ansiLevel = ansiLevel,
             ansiHyperLinks = hyperlinks,
             outputInteractive = outputInteractive,
             inputInteractive = inputInteractive,
-            crClearsLine = crClearsLine,
+            supportsAnsiCursor = supportsAnsiCursor,
         ),
         Size(width, height),
     )
@@ -96,7 +96,7 @@ class TerminalRecorder private constructor(
             ansiHyperLinks = hyperlinks ?: info.ansiHyperLinks,
             outputInteractive = outputInteractive ?: info.outputInteractive,
             inputInteractive = inputInteractive ?: info.inputInteractive,
-            crClearsLine = info.crClearsLine,
+            supportsAnsiCursor = info.supportsAnsiCursor,
         )
     }
 
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/widgets/ProgressLayout.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/widgets/ProgressLayout.kt
deleted file mode 100644
index 98acbc95..00000000
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/widgets/ProgressLayout.kt
+++ /dev/null
@@ -1,157 +0,0 @@
-@file:Suppress("DEPRECATION")
-
-package com.github.ajalt.mordant.widgets
-
-import com.github.ajalt.mordant.internal.DEFAULT_STYLE
-import com.github.ajalt.mordant.rendering.TextStyle
-import com.github.ajalt.mordant.rendering.Widget
-import com.github.ajalt.mordant.widgets.progress.*
-import com.github.ajalt.mordant.widgets.progress.ProgressState.Status.Finished
-import com.github.ajalt.mordant.widgets.progress.ProgressState.Status.Running
-import kotlin.time.Duration
-import kotlin.time.Duration.Companion.ZERO
-import kotlin.time.Duration.Companion.seconds
-import kotlin.time.DurationUnit
-import kotlin.time.TestTimeSource
-
-@Deprecated("Use progressBarLayout instead")
-open class ProgressBuilder internal constructor(
-    internal val builder: ProgressLayoutBuilder<Unit>,
-) {
-    var padding: Int = 2
-
-    /**
-     * Add a fixed text cell to this layout.
-     */
-    fun text(text: String) {
-        builder.text(text)
-    }
-
-    /**
-     * Add a percentage cell to this layout.
-     */
-    fun percentage() {
-        builder.percentage()
-    }
-
-    /**
-     * Add a progress bar cell to this layout.
-     *
-     * @param width The width in characters for this widget
-     * @param pendingChar (theme string: "progressbar.pending") The character to use to draw the pending portion of the bar in the active state.
-     * @param separatorChar (theme string: "progressbar.separator") The character to draw in between the competed and pending bar in the active state.
-     * @param completeChar (theme string: "progressbar.complete") The character to use to draw the completed portion of the bar in the active state.
-     * @param pendingStyle(theme style: "progressbar.pending") The style to use for the [pendingChar]s
-     * @param separatorStyle (theme style: "progressbar.separator") The style to use for the [separatorChar]
-     * @param completeStyle (theme style: "progressbar.complete") The style to use for the [completeChar] when completed < total
-     * @param finishedStyle (theme style: "progressbar.complete") The style to use for the [completeChar] when total <= completed
-     * @param indeterminateStyle e (theme style: "progressbar.separator") The style to use when the state us indeterminate
-     * @param showPulse (theme flag: "progressbar.pulse") If false, never draw the pulse animation in the indeterminate state.
-     */
-    fun progressBar(
-        width: Int? = null,
-        pendingChar: String? = null,
-        separatorChar: String? = null,
-        completeChar: String? = null,
-        pendingStyle: TextStyle? = null,
-        separatorStyle: TextStyle? = null,
-        completeStyle: TextStyle? = null,
-        finishedStyle: TextStyle? = null,
-        indeterminateStyle: TextStyle? = null,
-        showPulse: Boolean? = null,
-    ) {
-        builder.progressBar(
-            width,
-            pendingChar,
-            separatorChar,
-            completeChar,
-            pendingStyle,
-            separatorStyle,
-            completeStyle,
-            finishedStyle,
-            indeterminateStyle,
-            if (showPulse == false) ZERO else 2.seconds,
-        )
-    }
-
-    /**
-     * Add a cell that displays the current completed count to this layout.
-     */
-    fun completed(
-        suffix: String = "",
-        includeTotal: Boolean = true,
-        style: TextStyle = DEFAULT_STYLE,
-    ) {
-        builder.completed(suffix, includeTotal, style = style)
-    }
-
-    /**
-     * Add a cell that displays the current speed to this layout.
-     */
-    fun speed(suffix: String = "it/s", style: TextStyle = DEFAULT_STYLE) {
-        builder.speed(suffix, style)
-    }
-
-    /**
-     * Add a cell that displays the time remaining to this layout.
-     */
-    fun timeRemaining(prefix: String = "eta ", style: TextStyle = DEFAULT_STYLE) {
-        builder.timeRemaining(prefix, false, style = style)
-    }
-
-    /**
-     * Add a [Spinner] to this layout.
-     *
-     * @param spinner The spinner to display
-     * @param frameRate The number of times per second to advance the spinner's displayed frame
-     */
-    fun spinner(spinner: Spinner, frameRate: Int = 8) {
-        builder.spinner(spinner, fps = frameRate)
-    }
-}
-
-/**
- * A builder for creating an animated progress bar widget.
- */
-@Deprecated("Use progressBarLayout instead")
-class ProgressLayout internal constructor(
-    private val factory: ProgressBarDefinition<Unit>,
-) {
-    fun build(
-        completed: Long,
-        total: Long? = null,
-        elapsedSeconds: Double = 0.0,
-        completedPerSecond: Double? = null,
-    ): Widget {
-        val t = TestTimeSource()
-        val displayedTime = t.markNow()
-        t += elapsedSeconds.seconds
-        val speed = (completedPerSecond ?: calcHz(completed, elapsedSeconds.seconds))
-            .takeIf { it > 0 }
-        val status = when {
-            total != null && completed >= total -> Finished(displayedTime, displayedTime)
-            else -> Running(displayedTime)
-        }
-        return factory.build(
-            total,
-            completed,
-            displayedTime,
-            status,
-            speed = speed
-        )
-    }
-}
-
-private fun calcHz(completed: Long, elapsed: Duration): Double = when {
-    completed <= 0 || elapsed <= ZERO -> 0.0
-    else -> completed / elapsed.toDouble(DurationUnit.SECONDS)
-}
-
-/**
- * Build a [ProgressLayout]
- */
-@Deprecated("Use progressBarLayout instead")
-fun progressLayout(init: ProgressBuilder.() -> Unit): ProgressLayout {
-    val builder = ProgressBuilder(ProgressLayoutBuilder()).apply(init)
-    return ProgressLayout(builder.builder.build(builder.padding, true))
-}
diff --git a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/widgets/progress/ProgressBarWidgetMaker.kt b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/widgets/progress/ProgressBarWidgetMaker.kt
index 8f910fdb..ed5ee3db 100644
--- a/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/widgets/progress/ProgressBarWidgetMaker.kt
+++ b/mordant/src/commonMain/kotlin/com/github/ajalt/mordant/widgets/progress/ProgressBarWidgetMaker.kt
@@ -3,6 +3,7 @@ package com.github.ajalt.mordant.widgets.progress
 import com.github.ajalt.mordant.rendering.TextAlign
 import com.github.ajalt.mordant.rendering.Widget
 import com.github.ajalt.mordant.table.*
+import com.github.ajalt.mordant.table.ColumnWidth.Companion.Auto
 import com.github.ajalt.mordant.widgets.EmptyWidget
 import com.github.ajalt.mordant.widgets.Padding
 import kotlin.math.max
@@ -100,14 +101,14 @@ object MultiProgressBarWidgetMaker : ProgressBarWidgetMaker {
                     for ((j, row) in rows.withIndex()) {
                         val (d, _) = row
                         if (!d.alignColumns) continue // only aligned rows affect the column
-                        val w1 = width.toCustom()
-                        val w2 = d.cells.getOrNull(i)?.columnWidth?.toCustom() ?: continue
+                        val w1 = width
+                        val w2 = d.cells.getOrNull(i)?.columnWidth ?: continue
                         width = when {
                             w1.isExpand || w2.isExpand -> {
                                 ColumnWidth.Expand(nullMax(w1.expandWeight, w2.expandWeight) ?: 1f)
                             }
                             // If we had a MinWidth type, we'd use it here instead of Auto
-                            (j > 0 && w1.isAuto) || w2.isAuto -> ColumnWidth.Auto
+                            (j > 0 && w1.isAuto) || w2.isAuto -> Auto
                             else -> ColumnWidth.Fixed(nullMax(w1.width, w2.width)!!)
                         }
                     }
diff --git a/mordant/src/jvmMain/kotlin/com/github/ajalt/mordant/animation/ProgressAnimation.kt b/mordant/src/jvmMain/kotlin/com/github/ajalt/mordant/animation/ProgressAnimation.kt
deleted file mode 100644
index 8de10a9a..00000000
--- a/mordant/src/jvmMain/kotlin/com/github/ajalt/mordant/animation/ProgressAnimation.kt
+++ /dev/null
@@ -1,177 +0,0 @@
-@file:Suppress("DEPRECATION")
-
-package com.github.ajalt.mordant.animation
-
-import com.github.ajalt.mordant.animation.progress.*
-import com.github.ajalt.mordant.terminal.Terminal
-import com.github.ajalt.mordant.widgets.ProgressBuilder
-import com.github.ajalt.mordant.widgets.ProgressLayout
-import com.github.ajalt.mordant.widgets.progress.ANIMATION_FPS
-import com.github.ajalt.mordant.widgets.progress.ProgressBarDefinition
-import com.github.ajalt.mordant.widgets.progress.ProgressLayoutBuilder
-import com.github.ajalt.mordant.widgets.progress.TEXT_FPS
-import java.util.concurrent.Future
-import kotlin.time.Duration.Companion.seconds
-import kotlin.time.TimeSource
-
-
-@Deprecated("Use progressBarLayout instead")
-class ProgressAnimationBuilder internal constructor() : ProgressBuilder(
-    ProgressLayoutBuilder()
-) {
-    /**
-     * The maximum number of times per second to update idle animations like the progress bar pulse
-     * (default: 30fps)
-     */
-    var animationFrameRate: Int = 30
-
-    /**
-     * The maximum number of times per second to update text like the estimated time remaining.
-     * (default: 5fps)
-     */
-    var textFrameRate: Int = 5
-
-    /**
-     * The number of seconds worth of history to keep track of for estimating progress speed and
-     * time remaining (default: 30s)
-     */
-    var historyLength: Float = 30f
-}
-
-/**
- * A pretty animated progress bar. Manages a timer thread to update the progress bar, so be sure to [stop] it when you're done.
- */
-@Deprecated("Use progressBarLayout instead")
-class ProgressAnimation internal constructor(
-    private val inner: ThreadProgressTaskAnimator<Unit>,
-) {
-    private val lock = Any()
-    private var future: Future<*>? = null
-
-    /**
-     * Set the current progress to the [completed] value.
-     */
-    fun update(completed: Long) {
-        inner.update(completed)
-        update()
-    }
-
-    /**
-     * Set the current progress to the [completed] value.
-     */
-    fun update(completed: Int) {
-        update(completed.toLong())
-    }
-
-    /**
-     * Update the progress bar without changing the current progress amount.
-     *
-     * This will redraw the animation and update fields like the estimated time remaining.
-     */
-    fun update() {
-        inner.refresh()
-    }
-
-    /**
-     * Set the current progress to the [completed] value, and set the total to the [total] value.
-     */
-    fun update(completed: Long, total: Long?) {
-        inner.update {
-            this.completed = completed
-            this.total = total
-        }
-        update()
-    }
-
-    /**
-     * Set the [total] amount of work to be done, or `null` to make the progress bar indeterminate.
-     */
-    fun updateTotal(total: Long?) {
-        inner.update { this.total = total }
-        update()
-    }
-
-    /**
-     * Advance the current completed progress by [amount] without changing the total.
-     */
-    fun advance(amount: Long = 1) {
-        inner.advance(amount)
-        if (!inner.finished) {
-            update()
-        }
-    }
-
-    /**
-     * Start the progress bar animation.
-     */
-    fun start() = synchronized(lock) {
-        if (future != null) return
-        future = inner.execute()
-    }
-
-    /**
-     * Stop the progress bar animation.
-     *
-     * The progress bar will remain on the screen until you call [clear].
-     * You can call [start] again to resume the animation.
-     */
-    fun stop() = synchronized(lock) {
-        future?.cancel(false)
-        future = null
-    }
-
-    /**
-     * Set the progress to 0 and restart the animation.
-     */
-    fun restart() = synchronized(lock) {
-        inner.reset()
-        if (future == null) update()
-    }
-
-    /**
-     * Stop the animation and remove it from the screen.
-     *
-     * If you want to leave the animation on the screen, call [stop] instead.
-     */
-    fun clear() = synchronized(lock) {
-        stop()
-        inner.clear()
-    }
-}
-
-/**
- * Create an animated progress bar.
- *
- * See [ProgressLayout] for the types of cells that can be added.
- */
-@Deprecated("Use progressBarLayout instead")
-fun Terminal.progressAnimation(init: ProgressAnimationBuilder.() -> Unit): ProgressAnimation {
-    return progressAnimation(TimeSource.Monotonic, init)
-}
-
-// internal for testing
-internal fun Terminal.progressAnimation(
-    timeSource: TimeSource.WithComparableMarks,
-    init: ProgressAnimationBuilder.() -> Unit,
-): ProgressAnimation {
-    val builder = ProgressAnimationBuilder().apply(init)
-    val origDef = builder.builder.build(builder.padding, true)
-    // Since the new builder requires the fps upfront, we copy the cells and replace the fps
-    val cells = origDef.cells.mapTo(mutableListOf()) {
-        it.copy(
-            fps = when (it.fps) {
-                TEXT_FPS -> builder.textFrameRate
-                ANIMATION_FPS -> builder.animationFrameRate
-                else -> it.fps
-            }
-        )
-    }
-    val definition = ProgressBarDefinition(cells, origDef.spacing, origDef.alignColumns)
-    return ProgressAnimation(
-        definition.animateOnThread(
-            this,
-            timeSource = timeSource,
-            speedEstimateDuration = builder.historyLength.toDouble().seconds
-        )
-    )
-}
diff --git a/samples/detection/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt b/samples/detection/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
index 16d92e34..2084fb6b 100644
--- a/samples/detection/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
+++ b/samples/detection/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
@@ -11,7 +11,7 @@ fun main() {
     val theme = terminal.theme
     terminal.println(
         Panel(
-            Text(terminal.info.toString(), whitespace = NORMAL).withPadding(1),
+            Text(terminal.terminalInfo.toString(), whitespace = NORMAL).withPadding(1),
             Text(theme.info("Detected Terminal Info"))
         )
     )
diff --git a/samples/hexviewer/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt b/samples/hexviewer/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
index 774f7e69..fc67a031 100644
--- a/samples/hexviewer/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
+++ b/samples/hexviewer/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
@@ -5,6 +5,7 @@ import com.github.ajalt.mordant.rendering.TextStyle
 import com.github.ajalt.mordant.table.Borders
 import com.github.ajalt.mordant.table.table
 import com.github.ajalt.mordant.terminal.Terminal
+import com.github.ajalt.mordant.terminal.danger
 import okio.FileSystem
 import okio.Path.Companion.toPath
 import okio.SYSTEM
@@ -39,7 +40,7 @@ fun main(args: Array<String>) {
     }
 
     // 4 chars per octet, -20 for borders + address
-    val w = (terminal.info.width - 20) / 4
+    val w = (terminal.size.width - 20) / 4
     // round down to nearest multiple of 8
     val octetsPerRow = (w - w % 8).coerceAtLeast(1)
 
diff --git a/samples/select/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt b/samples/select/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
index 643fff9a..8154cc0c 100644
--- a/samples/select/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
+++ b/samples/select/src/commonMain/kotlin/com/github/ajalt/mordant/samples/main.kt
@@ -3,6 +3,8 @@ package com.github.ajalt.mordant.samples
 import com.github.ajalt.mordant.input.interactiveMultiSelectList
 import com.github.ajalt.mordant.input.interactiveSelectList
 import com.github.ajalt.mordant.terminal.Terminal
+import com.github.ajalt.mordant.terminal.danger
+import com.github.ajalt.mordant.terminal.success
 
 
 fun main() {


Test patch:
diff --git a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/animation/AnimationTest.kt b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/animation/AnimationTest.kt
index 041e5dae..fca98fa4 100644
--- a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/animation/AnimationTest.kt
+++ b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/animation/AnimationTest.kt
@@ -12,32 +12,6 @@ class AnimationTest {
     private val rec = TerminalRecorder(width = 24)
     private val t = Terminal(terminalInterface = rec)
 
-    @[Test JsName("no_trailing_linebreak")]
-    fun `no trailing linebreak`() {
-        val a = t.textAnimation<Int>(trailingLinebreak = false) { "<$it>\n===" }
-        a.update(1)
-        rec.normalizedOutput() shouldBe "<1>\n==="
-
-        // update
-        rec.clearOutput()
-        a.update(2)
-        val moves = t.cursor.getMoves { startOfLine(); up(1) }
-        rec.normalizedOutput() shouldBe "${moves}<2>\n==="
-    }
-
-    @[Test JsName("no_trailing_linebreak_single_line")]
-    fun `no trailing linebreak single line`() {
-        val a = t.textAnimation<Int>(trailingLinebreak = false) { "<$it>" }
-        a.update(1)
-        rec.normalizedOutput() shouldBe "<1>"
-
-        // update
-        rec.clearOutput()
-        a.update(2)
-        val moves = t.cursor.getMoves { startOfLine() }
-        rec.normalizedOutput() shouldBe "${moves}<2>"
-    }
-
     @[Test JsName("animation_size_change")]
     fun `animation size change`() {
         val a = t.textAnimation<String> { it }
@@ -53,7 +27,7 @@ class AnimationTest {
 
     @Test
     fun crClearsLine() {
-        val rec = TerminalRecorder(width = 24, crClearsLine = true)
+        val rec = TerminalRecorder(width = 24, supportsAnsiCursor = true)
         val t = Terminal(terminalInterface = rec)
         val a = t.textAnimation<Int> { "$it" }
         a.update(1)
diff --git a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/table/TableColumnWidthTest.kt b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/table/TableColumnWidthTest.kt
index a675332e..e187a0b3 100644
--- a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/table/TableColumnWidthTest.kt
+++ b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/table/TableColumnWidthTest.kt
@@ -167,7 +167,7 @@ class TableColumnWidthTest : RenderingTest() {
             overflowWrap = OverflowWrap.TRUNCATE
             whitespace = Whitespace.NORMAL
             column(0) { width = ColumnWidth.Fixed(3) }
-            column(1) { width = ColumnWidth.Custom(null, null, 4) }
+            column(1) { width = ColumnWidth(4) }
             column(3) { width = ColumnWidth.Expand(2) }
             body {
                 this.cellBorders = borders
diff --git a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/terminal/PromptTest.kt b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/terminal/PromptTest.kt
index 8897dad9..8f884c7c 100644
--- a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/terminal/PromptTest.kt
+++ b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/terminal/PromptTest.kt
@@ -42,7 +42,7 @@ class PromptTest {
 
     @[Test JsName("custom_Prompt")]
     fun `custom Prompt`() {
-        t.info.ansiLevel = AnsiLevel.NONE
+        t.terminalInfo.ansiLevel = AnsiLevel.NONE
         class IntPrompt : Prompt<Int>("pr", t) {
             override fun convert(input: String): ConversionResult<Int> {
                 return input.toIntOrNull()
diff --git a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/terminal/TerminalColorsTest.kt b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/terminal/TerminalColorsTest.kt
deleted file mode 100644
index 4bdaa813..00000000
--- a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/terminal/TerminalColorsTest.kt
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.github.ajalt.mordant.terminal
-
-import com.github.ajalt.colormath.model.*
-import com.github.ajalt.mordant.internal.CSI
-import com.github.ajalt.mordant.internal.DEFAULT_STYLE
-import com.github.ajalt.mordant.rendering.*
-import io.kotest.assertions.assertSoftly
-import io.kotest.data.blocking.forAll
-import io.kotest.data.row
-import io.kotest.matchers.shouldBe
-import kotlin.js.JsName
-import kotlin.test.Test
-
-@Suppress("DEPRECATION")
-class TerminalColorsTest {
-    private val c = Terminal(AnsiLevel.TRUECOLOR).colors
-
-    @[Test JsName("empty_string")]
-    fun `empty string`() = doTest(
-        c.blue(""),
-        ""
-    )
-
-    @[Test JsName("one_level_nesting")]
-    fun `one level nesting`() = doTest(
-        c.blue("A${c.red("B")}C"),
-        "<34>A<31>B<34>C<39>"
-    )
-
-    @[Test JsName("one_level_nesting_start_of_string")]
-    fun `one level nesting start of string`() = doTest(
-        (c.blue on c.green)("${c.red("A")}B"),
-        "<34;42>AB<39;49>"
-    )
-
-    @[Test JsName("one_level_nesting_end_of_string")]
-    fun `one level nesting end of string`() = doTest(
-        c.red("A${c.green("B")}"),
-        "<31>A<32>B<39>"
-    )
-
-    @[Test JsName("two_level_nesting")]
-    fun `two level nesting`() = doTest(
-        c.blue("A${c.red("B${c.green("C")}D")}E"),
-        "<34>A<31>B<32>C<31>D<34>E<39>"
-    )
-
-    @[Test JsName("two_level_nesting_end_of_string")]
-    fun `two level nesting end of string`() = doTest(
-        c.red("A${c.green("B${c.yellow("C")}")}"),
-        "<31>A<32>B<33>C<39>"
-    )
-
-    @[Test JsName("two_level_nesting_styles")]
-    fun `two level nesting styles`() = doTest(
-        c.red("A${c.bold("B${c.green("C")}D")}E"),
-        "<31>A<1>B<32>C<31>D<22>E<39>"
-    )
-
-    @[Test JsName("three_level_nesting_styles_and_bg")]
-    fun `three level nesting styles and bg`() = doTest(
-        c.run { (red on red)("A${(green on green)("B${(yellow.bg + underline)("C")}D")}E") },
-        "<31;41>A<32;42>B<43;4>C<42;24>D<31;41>E<39;49>"
-    )
-
-    @[Test JsName("all_ansi16_colors")]
-    fun `all ansi16 colors`() = forAll(
-        row(c.black, 30),
-        row(c.red, 31),
-        row(c.green, 32),
-        row(c.yellow, 33),
-        row(c.blue, 34),
-        row(c.magenta, 35),
-        row(c.cyan, 36),
-        row(c.white, 37),
-        row(c.gray, 90),
-        row(c.brightRed, 91),
-        row(c.brightGreen, 92),
-        row(c.brightYellow, 93),
-        row(c.brightBlue, 94),
-        row(c.brightMagenta, 95),
-        row(c.brightCyan, 96),
-        row(c.brightWhite, 97),
-    ) { color, code ->
-        color.color!!.toAnsi16().code shouldBe code
-    }
-
-    @[Test JsName("all_24bit_colors")]
-    fun `all 24bit colors`() = forAll(
-        row(c.rgb("#ff00ff"), RGB("#ff00ff")),
-        row(c.rgb(.11, .22, .33), RGB(.11, .22, .33)),
-        row(c.hsl(.11, .22, .33), HSL(.11, .22, .33)),
-        row(c.hsv(11, .22, .33), HSV(11, .22, .33)),
-        row(c.cmyk(11, 22, 33, 44), CMYK(11, 22, 33, 44)),
-        row(c.gray(0.5), RGB(.5, .5, .5)),
-        row(c.xyz(.11, .22, .33), XYZ(.11, .22, .33)),
-        row(c.lab(11, 22, 33), LAB(11, 22, 33)),
-    ) { color, expected ->
-        color.color shouldBe expected
-    }
-
-    @[Test JsName("all_styles")]
-    fun `all styles`() {
-        assertSoftly {
-            c.bold.bold shouldBe true
-            c.dim.dim shouldBe true
-            c.italic.italic shouldBe true
-            c.underline.underline shouldBe true
-            c.inverse.inverse shouldBe true
-            c.strikethrough.strikethrough shouldBe true
-            c.plain shouldBe DEFAULT_STYLE
-        }
-    }
-
-    @[Test JsName("all_colors_and_styles_downsampled")]
-    fun `all colors and styles downsampled`() {
-        val colorNone = Terminal(ansiLevel = AnsiLevel.NONE).colors
-        val colorRgb = Terminal(ansiLevel = AnsiLevel.TRUECOLOR).colors
-        forAll(
-            row({ it.black }, TextColors.black),
-            row({ it.red }, TextColors.red),
-            row({ it.green }, TextColors.green),
-            row({ it.yellow }, TextColors.yellow),
-            row({ it.blue }, TextColors.blue),
-            row({ it.magenta }, TextColors.magenta),
-            row({ it.cyan }, TextColors.cyan),
-            row({ it.white }, TextColors.white),
-            row({ it.gray }, TextColors.gray),
-            row({ it.brightRed }, TextColors.brightRed),
-            row({ it.brightGreen }, TextColors.brightGreen),
-            row({ it.brightYellow }, TextColors.brightYellow),
-            row({ it.brightBlue }, TextColors.brightBlue),
-            row({ it.brightMagenta }, TextColors.brightMagenta),
-            row({ it.brightCyan }, TextColors.brightCyan),
-            row({ it.brightWhite }, TextColors.brightWhite),
-            row({ it.bold }, TextStyles.bold.style),
-            row({ it.dim }, TextStyles.dim.style),
-            row({ it.italic }, TextStyles.italic.style),
-            row({ it.underline }, TextStyles.underline.style),
-            row({ it.inverse }, TextStyles.inverse.style),
-            row({ it.strikethrough }, TextStyles.strikethrough.style),
-            row({ it.plain }, DEFAULT_STYLE),
-            row({ it.success }, Theme.Default.success),
-            row({ it.danger }, Theme.Default.danger),
-            row({ it.warning }, Theme.Default.warning),
-            row({ it.info }, Theme.Default.info),
-            row({ it.muted }, Theme.Default.muted),
-        ) { block: (TerminalColors) -> TextStyle, style: TextStyle ->
-            block(colorNone) shouldBe DEFAULT_STYLE
-            block(colorRgb) shouldBe style
-        }
-    }
-
-    private fun doTest(actual: String, expected: String) {
-        try {
-            actual.replace(CSI, "<").replace("m", ">") shouldBe expected
-        } catch (e: Throwable) {
-            println("Expected:")
-            println(expected.replace("<", CSI).replace(">", "m"))
-            println("Actual:")
-            println(actual)
-            throw e
-        }
-    }
-}
diff --git a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/widgets/DeprecatedProgressLayoutTest.kt b/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/widgets/DeprecatedProgressLayoutTest.kt
deleted file mode 100644
index a494eff3..00000000
--- a/mordant/src/commonTest/kotlin/com/github/ajalt/mordant/widgets/DeprecatedProgressLayoutTest.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.github.ajalt.mordant.widgets
-
-import com.github.ajalt.mordant.rendering.TextColors
-import com.github.ajalt.mordant.rendering.Theme
-import com.github.ajalt.mordant.test.RenderingTest
-import kotlin.js.JsName
-import kotlin.test.Test
-
-@Suppress("DEPRECATION")
-class DeprecatedProgressLayoutTest : RenderingTest() {
-    private val indetermStyle = Theme.Default.style("progressbar.indeterminate")
-
-    @Test
-    fun indeterminate() = doTest(
-        "text.txt|  0%|#########################|     0/---.-B| ---.-it/s",
-        0
-    )
-
-    @[Test JsName("no_progress")]
-    fun `no progress`() = doTest(
-        "text.txt|  0%|.........................|         0/0B| ---.-it/s",
-        0, 0
-    )
-
-    @[Test JsName("large_values")]
-    fun `large values`() = doTest(
-        "text.txt| 50%|############>............|150.0/300.0MB|100.0Mit/s",
-        150_000_000, 300_000_000, 1.5, 100_000_000.0
-    )
-
-    @[Test JsName("short_eta")]
-    fun `short eta`() = doTest(
-        "text.txt| 50%|############>............|         1/2B|   4.0it/s",
-        1, 2, 3.0, 4.0
-    )
-
-    @[Test JsName("automatic_eta")]
-    fun `automatic eta`() = doTest(
-        "text.txt| 50%|############>............|         1/2B|   0.3it/s",
-        1, 2, 3.0
-    )
-
-    @[Test JsName("long_eta")]
-    fun `long eta`() = doTest(
-        "text.txt| 50%|############>............|150.0/300.0MB|   2.0it/s",
-        150_000_000, 300_000_000, 1.5, 2.0
-    )
-
-    @Test
-    fun defaultPadding() = checkRender(
-        progressLayout {
-            text("1")
-            percentage()
-            text("2")
-            speed()
-            text("3")
-        }.build(0, 0, 0.0, 0.0),
-        "1    0%  2   ---.-it/s  3",
-    )
-
-    @Test
-    fun pulse() = checkRender(
-        progressLayout {
-            progressBar()
-        }.build(0, null, 1.0, 0.0),
-        indetermStyle("━${TextColors.rgb(1, 1, 1)("━")}━"),
-        width = 3,
-    )
-
-    @[Test JsName("no_pulse")]
-    fun `no pulse`() = checkRender(
-        progressLayout {
-            progressBar(showPulse = false)
-        }.build(0, null, 1.0, 0.0),
-        indetermStyle("━━━"),
-        width = 3,
-    )
-
-    private fun doTest(
-        expected: String,
-        completed: Long,
-        total: Long? = null,
-        elapsedSeconds: Double = 0.0,
-        completedPerSecond: Double? = null,
-    ) = checkRender(
-        progressLayout {
-            padding = 0
-            text("text.txt")
-            text("|")
-            percentage()
-            text("|")
-            progressBar()
-            text("|")
-            completed(suffix = "B")
-            text("|")
-            speed()
-        }.build(completed, total, elapsedSeconds, completedPerSecond),
-        expected,
-        width = 64,
-        theme = Theme(Theme.PlainAscii) { strings["progressbar.pending"] = "." },
-    )
-}
diff --git a/mordant/src/jvmTest/kotlin/com/github/ajalt/mordant/animation/DeprecatedProgressAnimationTest.kt b/mordant/src/jvmTest/kotlin/com/github/ajalt/mordant/animation/DeprecatedProgressAnimationTest.kt
deleted file mode 100644
index 03e18e0c..00000000
--- a/mordant/src/jvmTest/kotlin/com/github/ajalt/mordant/animation/DeprecatedProgressAnimationTest.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.github.ajalt.mordant.animation
-
-import com.github.ajalt.mordant.internal.CSI
-import com.github.ajalt.mordant.rendering.Theme
-import com.github.ajalt.mordant.terminal.Terminal
-import com.github.ajalt.mordant.terminal.TerminalRecorder
-import com.github.ajalt.mordant.test.RenderingTest
-import com.github.ajalt.mordant.test.latestOutput
-import io.kotest.matchers.shouldBe
-import kotlin.test.Test
-import kotlin.time.Duration.Companion.seconds
-import kotlin.time.TestTimeSource
-
-class DeprecatedProgressAnimationTest : RenderingTest() {
-    private val now = TestTimeSource()
-    private val vt = TerminalRecorder(width = 56)
-    private val t = Terminal(
-        theme = Theme(Theme.PlainAscii) { strings["progressbar.pending"] = "." },
-        terminalInterface = vt
-    )
-
-    @Test
-    fun throttling() {
-        val pt = t.progressAnimation(now) {
-            textFrameRate = 1
-            padding = 0
-            speed()
-            text("|")
-            timeRemaining()
-        }
-
-        pt.update(0, 1000)
-        vt.latestOutput() shouldBe " ---.-it/s|eta -:--:--"
-
-        now += 0.5.seconds
-        vt.clearOutput()
-        pt.update(40)
-        vt.latestOutput() shouldBe " ---.-it/s|eta -:--:--"
-
-        now += 0.1.seconds
-        vt.clearOutput()
-        pt.update()
-        vt.latestOutput() shouldBe " ---.-it/s|eta -:--:--"
-
-        now += 0.4.seconds
-        vt.clearOutput()
-        pt.update()
-        vt.latestOutput() shouldBe "  40.0it/s|eta 0:00:24"
-
-        now += 0.9.seconds
-        vt.clearOutput()
-        pt.update()
-        vt.latestOutput() shouldBe "  40.0it/s|eta 0:00:24"
-    }
-
-    @Test
-    fun animation() {
-        val pt = t.progressAnimation(now) {
-            textFrameRate = 1
-            padding = 0
-            text("text.txt")
-            text("|")
-            percentage()
-            text("|")
-            progressBar()
-            text("|")
-            completed()
-            text("|")
-            speed()
-            text("|")
-            timeRemaining()
-        }
-        pt.update(0, 100)
-        vt.latestOutput() shouldBe "text.txt|  0%|......|       0/100| ---.-it/s|eta -:--:--"
-
-        now += 10.0.seconds
-        vt.clearOutput()
-        pt.update(40)
-        vt.latestOutput() shouldBe "text.txt| 40%|##>...|      40/100|   4.0it/s|eta 0:00:15"
-
-        now += 10.0.seconds
-        vt.clearOutput()
-        pt.update()
-        vt.latestOutput() shouldBe "text.txt| 40%|##>...|      40/100|   2.0it/s|eta 0:00:30"
-
-        now += 10.0.seconds
-        vt.clearOutput()
-        pt.updateTotal(200)
-        vt.latestOutput() shouldBe "text.txt| 20%|#>....|      40/200|   1.3it/s|eta 0:02:00"
-
-        vt.clearOutput()
-        pt.restart()
-        vt.latestOutput() shouldBe "text.txt|  0%|......|       0/200| ---.-it/s|eta -:--:--"
-
-        vt.clearOutput()
-        pt.clear()
-        val moves = t.cursor.getMoves { startOfLine(); clearScreenAfterCursor() }
-        vt.output() shouldBe "$moves$CSI?25h"
-    }
-}