Skip to content

Commit 1a9ea44

Browse files
Adjective-ObjectMax Huang-Hobbs
and
Max Huang-Hobbs
authored
feat: support multiline tea.Println() messages (charmbracelet#490)
* don't truncate multi-line printf in std renderer When logging something into the scrollback history of the standard renderer, the current approach temporarially increases the size of the UI by the number of logged messages. This has 2 issues: - log lines are truncated according to the current width of the terminal UI. This truncation behaviour is desireable when writing into the TUI's controlled space, but is not desireable when Printf()ing messages into the scrollback, since the contents of the logged line will be truncated with no way to recover the history. - User code pre-wrapping messages they want to print to the scrollback don't behave the way that you would want/expect log lines in a terminal to behave: - Resizing the terminal emulator does not reflow the lines to the new terminal's width - Manual wrapping breaks most terminal emulator's detection of clickable URLs and file paths This change replaces that approach with a full clear of the previos UI + printing unwrapped messages into the terminal before the next render this has a minor performance impact because it necessitates a full clear of the terminal UI on each Printf(). This breaks duplicate line detection between renders. However, the current approach will rarely hit duplicate line detection, since adding log messages to the front of the printout buffer offsets the new buffer. Therefore, the current line detection logic will only trigger when the buffer contains duplicate lines offset by the number of messages being logged in this render pass. * remove stray comment --------- Co-authored-by: Max Huang-Hobbs <[email protected]>
1 parent da49e8f commit 1a9ea44

File tree

1 file changed

+19
-10
lines changed

1 file changed

+19
-10
lines changed

standard_renderer.go

+19-10
Original file line numberDiff line numberDiff line change
@@ -173,19 +173,18 @@ func (r *standardRenderer) flush() {
173173
skipLines := make(map[int]struct{})
174174
flushQueuedMessages := len(r.queuedMessageLines) > 0 && !r.altScreenActive
175175

176-
// Add any queued messages to this render
177-
if flushQueuedMessages {
178-
newLines = append(r.queuedMessageLines, newLines...)
179-
r.queuedMessageLines = []string{}
180-
}
181-
182176
// Clear any lines we painted in the last render.
183177
if r.linesRendered > 0 {
184178
for i := r.linesRendered - 1; i > 0; i-- {
185-
// If the number of lines we want to render hasn't increased and
186-
// new line is the same as the old line we can skip rendering for
187-
// this line as a performance optimization.
188-
if (len(newLines) <= len(oldLines)) && (len(newLines) > i && len(oldLines) > i) && (newLines[i] == oldLines[i]) {
179+
// if we are clearing queued messages, we want to clear all lines, since
180+
// printing messages allows for native terminal word-wrap, we
181+
// don't have control over the queued lines
182+
if flushQueuedMessages {
183+
out.ClearLine()
184+
} else if (len(newLines) <= len(oldLines)) && (len(newLines) > i && len(oldLines) > i) && (newLines[i] == oldLines[i]) {
185+
// If the number of lines we want to render hasn't increased and
186+
// new line is the same as the old line we can skip rendering for
187+
// this line as a performance optimization.
189188
skipLines[i] = struct{}{}
190189
} else if _, exists := r.ignoreLines[i]; !exists {
191190
out.ClearLine()
@@ -215,6 +214,16 @@ func (r *standardRenderer) flush() {
215214
skipLines[k] = v
216215
}
217216

217+
if flushQueuedMessages {
218+
// Dump the lines we've queued up for printing
219+
for _, line := range r.queuedMessageLines {
220+
_, _ = out.WriteString(line)
221+
_, _ = out.WriteString("\r\n")
222+
}
223+
// clear the queued message lines
224+
r.queuedMessageLines = []string{}
225+
}
226+
218227
// Paint new lines
219228
for i := 0; i < len(newLines); i++ {
220229
if _, skip := skipLines[i]; skip {

0 commit comments

Comments
 (0)