-
Notifications
You must be signed in to change notification settings - Fork 249
Add TerminalBuffer & TerminalCursor, parse \n \r \b, and more escape codes #85
base: master
Are you sure you want to change the base?
Conversation
} | ||
|
||
/// This method is called for each UTF-8 character that is received. | ||
/// It should perform state changes based on that character, then | ||
/// return an attributed string that renders the character | ||
private func handle(_ character: Character) -> (output: NSAttributedString?, didEnd: Bool) { | ||
// | ||
// swiftlint:disable cyclomatic_complexity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to disable the swiftlint error in this method instead of splitting it up into smaller methods. This method basically models a state machine, and doesn't do much other than change states and call delegate methods. It would, in my opinion, reduce readability a lot if I were to move the inner switches into methods and call those.
@louisdh thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine.
@@ -175,7 +175,7 @@ enum ANSIFontState: Int { | |||
|
|||
struct ANSITextState { | |||
var foregroundColor: UIColor = UserDefaultsController.shared.terminalTextColor | |||
var backgroundColor: UIColor = UserDefaultsController.shared.terminalBackgroundColor | |||
var backgroundColor: UIColor = .clear |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, switching background colors while terminal is open will not keep remnants of the background color visible where text was printed.
Tests were added for both new classes. The |
One regression I didn't address here: The OutputSanitizer (replace Does anyone have feedback on what should be done? Is that replacement necessary? We could sanitize after every character is printed, but that seems too expensive. |
The OutputSanitizer is quite necessary for a nice user experience in my opinion. On top of that, it might be required for App Store approval. I'm speculating here, but Apple may not like an app displaying paths containing "/private/var/mobile/...". |
Great work btw, making OpenTerm behave more like established terminals is a nice improvement. Also good to see some tests. |
Thanks! Assuming that the sanitizer won't ever need to replace multiple lines at once, we could avoid displaying each character as it comes in. Whenever we receive \r, \n, etc, or the input ends, run the sanitizer then display the full line . |
This is ready to merge now.
|
Two unit tests are failing in the latest commit of this branch: |
6e4801e
to
d09ebcd
Compare
Sorry about that, tests were broken with OutputSanitizer change. They are back up now 🙂 |
* Added libtext.dylib to OpenTerm * Fixed share stdin
300b802
to
55804dc
Compare
Is this good to merge? |
We will need additional validation before it ships, as it may break some commands. Lets keep it in this branch for a while, until I have more confidence in its correctness. |
Now that OpenTerm 2.0 is done, it would be great to get this PR up to date. Would it be possible to fix all these conflicts? |
I’ll take a look ASAP! |
This change adds another layer between the
Parser
andTerminalTextView
called theTerminalBuffer
(referred to as the "buffer"). The buffer contains an NSTextStorage (NSMutableAttributedString subclass) that theTerminalTextView
reads from.The buffer is responsible for adding new text that comes in to the proper position in the text storage. It uses the
TerminalCursor
(referred to as the "cursor") to keep track of where it needs to insert new text.Parsing
The buffer is now the Parser's delegate, and receives events from the Parser, some of which are:
\n
)\r
)Depending on what the Parser sends, the buffer will update the cursor's position and/or modify the text storage.
Cursor
The cursor (different than the UITextView's cursor), keeps track of a position within the text storage. It's only valid for a single text storage. It has a readable x,y coordinate, as well as an offset (current distance from the beginning of the storage).
The cursor contains mutating methods that adjust its state, and is not able to be modified except through those methods. Every time the x, y, or offset change, it makes sure to keep the other values in sync.
Example
In this example, I'll demonstrate what happens when a carriage return is received while parsing.
At the beginning, the storage contains a 2-line string, and the cursor is right after the last character of the first word:
Now, when a carriage return is received, the
parserDidReceiveCarriageReturn(_:)
method is called by theParser
. After this is handled, here is the state:Now, if more text comes in from the parser - "bonjour", here is the end state: