Skip to content

Commit

Permalink
Support multiline tea.Println() messages
Browse files Browse the repository at this point in the history
Normally, consumers are required to make their UI aware of the terminal
size, and printed output is truncated to the size of the terminal.
This is so the cursor will always end up in a predicatable vertical
position for rendering.

However, when printing messages from tea.Println() scrollback mode,
there are a number of reasons to allow lines to wrap:

- tea.Println() messages are not part of the re-drawn UI, so their
  wrapping does not affect our measurement of the UI height.
  This is what _would_ be messed if ui messages were to wrap in the
  terminal.
- tea.Println() messages are usually used for status updates, and
  truncating those messages makes them no longer useful.

In order to avoid truncation, the consumer may manually wrap lines,
however:

- Since messages are printed and never re-rendered, resizing the
  terminal in the future will not re-wrap the lines to the new terminal
  width
- Terminal emulators will not recognize clickable text (filepaths, urls)
  that have been manually wrapped across multiple lines, as the `\r\n`
  in the middle of the text will break most terminal emulators'
  recognition
  • Loading branch information
Adjective-Object committed Oct 6, 2022
1 parent f406999 commit 34c25e7
Showing 1 changed file with 14 additions and 1 deletion.
15 changes: 14 additions & 1 deletion standard_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,15 @@ func (r *standardRenderer) flush() {
out := termenv.NewOutput(buf)

newLines := strings.Split(r.buf.String(), "\n")
printlnMessagesThisFlush := 0
numLinesThisFlush := len(newLines)
oldLines := strings.Split(r.lastRender, "\n")
skipLines := make(map[int]struct{})
flushQueuedMessages := len(r.queuedMessageLines) > 0 && !r.altScreenActive

// Add any queued messages to this render
if flushQueuedMessages {
printlnMessagesThisFlush = len(r.queuedMessageLines)
newLines = append(r.queuedMessageLines, newLines...)
r.queuedMessageLines = []string{}
}
Expand Down Expand Up @@ -186,6 +188,7 @@ func (r *standardRenderer) flush() {
}
} else {
line := newLines[i]
isPrintlnMessage := i < printlnMessagesThisFlush

// Truncate lines wider than the width of the window to avoid
// wrapping, which will mess up rendering. If we don't have the
Expand All @@ -194,8 +197,18 @@ func (r *standardRenderer) flush() {
// Note that on Windows we only get the width of the window on
// program initialization, so after a resize this won't perform
// correctly (signal SIGWINCH is not supported on Windows).
//
// Exception: if this is a println, we _do_ want to allow
// wrapping since this scrollback should wrap instead of
// truncating
//
// This shows the whole scrollback message, as well as
// allowing modern terminal emulators to recognize filepaths
// and urls across line breaks
if r.width > 0 {
line = truncate.String(line, uint(r.width))
if !isPrintlnMessage {
line = truncate.String(line, uint(r.width))
}
}

_, _ = out.WriteString(line)
Expand Down

0 comments on commit 34c25e7

Please sign in to comment.