1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.metalava.cli.common
18 
19 enum class TerminalColor(val value: Int) {
20     BLACK(0),
21     RED(1),
22     GREEN(2),
23     YELLOW(3),
24     BLUE(4),
25     MAGENTA(5),
26     CYAN(6),
27     WHITE(7)
28 }
29 
30 val plainTerminal: Terminal = PlainTerminal()
31 val stylingTerminal: Terminal = StylingTerminal()
32 
33 sealed class Terminal {
attributesnull34     abstract fun attributes(
35         bold: Boolean = false,
36         italic: Boolean = false,
37         underline: Boolean = false,
38         reverse: Boolean = false,
39         foreground: TerminalColor? = null,
40         background: TerminalColor? = null
41     ): String
42 
43     abstract fun reset(): String
44 
45     fun bold(string: String): String {
46         return "${attributes(bold = true)}$string${reset()}"
47     }
48 
italicnull49     fun italic(string: String): String {
50         return "${attributes(italic = true)}$string${reset()}"
51     }
52 
colorizenull53     fun colorize(string: String, color: TerminalColor): String {
54         return "${attributes(foreground = color)}$string${reset()}"
55     }
56 }
57 
58 @Suppress("CanSealedSubClassBeObject")
59 private class PlainTerminal : Terminal() {
attributesnull60     override fun attributes(
61         bold: Boolean,
62         italic: Boolean,
63         underline: Boolean,
64         reverse: Boolean,
65         foreground: TerminalColor?,
66         background: TerminalColor?
67     ): String {
68         return ""
69     }
70 
resetnull71     override fun reset(): String {
72         return ""
73     }
74 }
75 
76 @Suppress("CanSealedSubClassBeObject")
77 private class StylingTerminal : Terminal() {
attributesnull78     override fun attributes(
79         bold: Boolean,
80         italic: Boolean,
81         underline: Boolean,
82         reverse: Boolean,
83         foreground: TerminalColor?,
84         background: TerminalColor?
85     ): String {
86         val sb = StringBuilder()
87         sb.append("\u001B[")
88         if (foreground != null) {
89             sb.append('3').append('0' + foreground.value)
90         }
91         if (background != null) {
92             if (sb.last().isDigit()) sb.append(';')
93             sb.append('4').append('0' + background.value)
94         }
95         if (bold) {
96             if (sb.last().isDigit()) sb.append(';')
97             sb.append('1')
98         }
99         if (italic) {
100             if (sb.last().isDigit()) sb.append(';')
101             sb.append('3')
102         }
103         if (underline) {
104             if (sb.last().isDigit()) sb.append(';')
105             sb.append('4')
106         }
107         if (reverse) {
108             if (sb.last().isDigit()) sb.append(';')
109             sb.append('7')
110         }
111         if (sb.last() == '[') {
112             // Nothing: Reset
113             sb.append('0')
114         }
115         sb.append("m")
116         return sb.toString()
117     }
118 
resetnull119     override fun reset(): String {
120         return "\u001b[0m"
121     }
122 }
123