Last active
May 30, 2020 14:32
-
-
Save maximkrouk/24a114058187c0cc94a54929f4ba6b07 to your computer and use it in GitHub Desktop.
Class for stdout redirection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Combine | |
class REPL { | |
private static let shared = REPL() | |
public static var publisher: AnyPublisher<String, Never> { | |
shared.publisher.eraseToAnyPublisher() | |
} | |
public typealias Publisher = PassthroughSubject<String, Never> | |
public let publisher = Publisher() | |
private let stdOut = Pipe() | |
private var buffer = Buffer() | |
private init() { setup() } | |
public func setup() { | |
printWarning() | |
setvbuf(stdout, nil, _IONBF, 0) | |
dup2(stdOut.fileHandleForWriting.fileDescriptor, STDOUT_FILENO) | |
stdOut.fileHandleForReading.readabilityHandler = { [weak self] handle in | |
guard | |
let self = self, | |
let output = self.buffer.append(handle.availableData) | |
else { return } | |
self.publisher.send(output) | |
} | |
} | |
private func printWarning( | |
file: String = #file, | |
line: UInt = #line, | |
function: String = #function | |
) { | |
print("⚠️ WARNING: STDOUT WILL BE OVERRIDEN BY REPL INSTANCE") | |
print("file:", file) | |
print("line:", line) | |
print("function:", function) | |
print("✅ It's fine if you expect it to happen.") | |
print("Output will be redirected to \(stdOut)") | |
print("You can read it from this fileHandle:", stdOut.fileHandleForReading) | |
} | |
} | |
extension REPL { | |
private struct Buffer { | |
private var storage = Data() | |
mutating func append(_ data: Data) -> String? { | |
storage.append(data) | |
if let string = String(data: storage, encoding: .utf8), | |
string.last?.isNewline == true | |
{ | |
buffer.removeAll() | |
return string | |
} | |
return nil | |
} | |
} | |
} |
Removed stderr
redirection due to fatal errors, bad access and other system errors, which is inconvenient for the case, when app crashes.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage
How does it work
REPL
REPL creates a new pipe for handling console output
Then sets this pipe as a new stdout
Handle output with buffer
Publish result if present
REPL.Buffer
storage: Data
to be a bufferappend
method was a newline then it returns storage contents and clears it.Sources:
See also:
Back to index