-
-
Notifications
You must be signed in to change notification settings - Fork 56
Expand file tree
/
Copy pathConsole+Ephemeral.swift
More file actions
120 lines (113 loc) · 4.19 KB
/
Copy pathConsole+Ephemeral.swift
File metadata and controls
120 lines (113 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/// Adds the ability to dynamically clear pre-defined sections of outputted text.
///
/// This is useful for creating interactive console applications that can guide users
/// through a process and then clean up the terminal before continuing.
///
/// ```swift
/// console.print("Logging in...")
/// if !loggedIn {
/// // all output after this call can be cleared by calling `popEphemeral()`
/// console.pushEphemeral()
///
/// // ask the user some questions
/// let password = console.ask("Enter password:")
/// // login with password ...
///
/// // clear all output since `pushEphemeral()`
/// console.popEphemeral()
/// } else {
/// // already logged in
/// }
/// console.print("Logged in!")
/// console.print("Doing something...")
/// ```
///
/// ``Console``s supporting this must call ``Console/didOutputLines(count:)`` every time text is outputted to the console
/// so that the number of lines to clear can be tracked.
extension Console {
/// Pushes a new ephemeral console state. All text outputted to the console immidiately after this call
/// can be cleared by using ``Console/popEphemeral()``.
///
/// This method can be called as many times as desired. Calls to ``Console/popEphemeral()`` will work in reverse order.
///
/// ```swift
/// console.print("a")
/// console.pushEphemeral()
/// console.print("b")
/// console.print("c")
/// console.pushEphemeral()
/// console.print("d")
/// console.print("e")
/// console.print("f")
/// console.popEphemeral() // removes "d", "e", and "f" lines
/// console.print("g")
/// console.popEphemeral() // removes "b", "c", and "g" lines
/// // just "a" has been printed now
/// ```
public func pushEphemeral() {
depth += 1
levels[depth] = 0
}
/// Pops a previous ephemeral console state. All text outputted to the console immidiately after the last call
/// to ``Console/pushEphemeral()`` will be cleared.
///
/// This method can be called once for each call to ``Console/pushEphemeral()``.
///
/// ```swift
/// console.print("a")
/// console.pushEphemeral()
/// console.print("b")
/// console.print("c")
/// console.pushEphemeral()
/// console.print("d")
/// console.print("e")
/// console.print("f")
/// console.popEphemeral() // removes "d", "e", and "f" lines
/// console.print("g")
/// console.popEphemeral() // removes "b", "c", and "g" lines
/// // just "a" has been printed now
/// ```
public func popEphemeral() {
precondition(depth > 0, "popEphemeral() must be called (once) after pushEphemeral()")
let lines = levels[depth] ?? 0
guard lines > 0 else {
levels[depth] = nil
depth -= 1
return
}
clear(lines: lines)
// remember to reset depth after or else
// the lines will get messed up
levels[depth] = nil
depth -= 1
}
/// This method allows the ``Console`` implementation to record how many lines have been printed so
/// that ``Console/pushEphemeral()`` and ``Console/popEphemeral()`` knows how many lines to clear.
///
/// > Note: This method should only be used by ``Console`` implementations.
public func didOutputLines(count: Int) {
guard self.depth > 0 else {
// not in an ephemeral state
return
}
if let existing = levels[self.depth] {
self.levels[self.depth] = existing + count
} else {
self.levels[self.depth] = count
}
}
/// Tracks how many successive calls to ``Console/pushEphemeral()`` have been made.
///
/// Calling ``Console/popEphemeral()`` will decrement this number.
private(set) var depth: Int {
get { return (self.userInfo["depth"] as? Int) ?? 0 }
set { self.userInfo["depth"] = newValue }
}
/// Stores how many lines have been outputted at each depth.
///
/// Calling ``Console/didOutputLines(count:)`` will increase this number for the current depth.
private var levels: [Int: Int] {
get { return (userInfo["levels"] as? [Int: Int]) ?? [:] }
set { self.userInfo["levels"] = newValue }
}
}