Skip to content

Commit

Permalink
Merge #11202 #11319
Browse files Browse the repository at this point in the history
11202: [color] Use graphemes to measure strings. r=pgavlin a=pgavlin

The number of Unicode code points in a string is not the same as the
number of user-visible characters (graphemes). When measuring colorized
strings, we want the latter rather than the former. Notably, these
changes fix some issues where the interactive display cut off before the
right edge of the terminal.

11319: Add prelim interface contract for Capabilities API r=caseyyh a=caseyyh

# Description

Add request shapes for Capabilities API, which will moving forward help cement service/client contract in dynamically indicating which features are available in a given backend for the CLI to use.

Related: https://github.com/pulumi/pulumi-service/issues/10510

## Checklist

<!--- Please provide details if the checkbox below is to be left unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my feature works
<!--- 
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the Pulumi Service,
then the service should honor older versions of the CLI where this change would not exist.
You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Service API version
  <!-- `@Pulumi` employees: If yes, you must submit corresponding changes in the service repo. -->


Co-authored-by: Pat Gavlin <pat@pulumi.com>
Co-authored-by: Casey <casey@pulumi.com>
  • Loading branch information
3 people committed Nov 10, 2022
3 parents e6e027e + 62dc0b1 + abe092c commit 572912f
Show file tree
Hide file tree
Showing 25 changed files with 9,021 additions and 8,930 deletions.
@@ -0,0 +1,4 @@
changes:
- type: fix
scope: cli/display
description: Fix text cutting off prior to the edge of the terminal
4 changes: 1 addition & 3 deletions pkg/backend/display/jsonmessage.go
Expand Up @@ -193,9 +193,7 @@ func (r *messageRenderer) tick(display *ProgressDisplay) {
func (r *messageRenderer) renderRow(display *ProgressDisplay,
id string, colorizedColumns []string, maxColumnLengths []int) {

uncolorizedColumns := display.uncolorizeColumns(colorizedColumns)

row := renderRow(colorizedColumns, uncolorizedColumns, maxColumnLengths)
row := renderRow(colorizedColumns, maxColumnLengths)
if r.isInteractive {
// Ensure we don't go past the end of the terminal. Note: this is made complex due to
// msgWithColors having the color code information embedded with it. So we need to get
Expand Down
57 changes: 15 additions & 42 deletions pkg/backend/display/progress.go
Expand Up @@ -25,7 +25,6 @@ import (
"strings"
"time"
"unicode"
"unicode/utf8"

"github.com/pulumi/pulumi/pkg/v3/backend/display/internal/terminal"
"github.com/pulumi/pulumi/pkg/v3/engine"
Expand Down Expand Up @@ -138,10 +137,6 @@ type ProgressDisplay struct {
// Maps used so we can generate short IDs for resource urns.
urnToID map[resource.URN]string

// Cache of colorized to uncolorized text. We go between the two a lot, so caching helps
// prevent lots of recomputation
colorizedToUncolorized map[string]string

// Structure that tracks the time taken to perform an action on a resource.
opStopwatch opStopwatch
}
Expand Down Expand Up @@ -260,20 +255,19 @@ func ShowProgressEvents(op string, action apitype.UpdateKind, stack tokens.Name,
}

display := &ProgressDisplay{
action: action,
isPreview: isPreview,
isTerminal: isInteractive,
opts: opts,
renderer: renderer,
stack: stack,
proj: proj,
eventUrnToResourceRow: make(map[resource.URN]ResourceRow),
suffixColumn: int(statusColumn),
suffixesArray: []string{"", ".", "..", "..."},
urnToID: make(map[resource.URN]string),
colorizedToUncolorized: make(map[string]string),
displayOrderCounter: 1,
opStopwatch: newOpStopwatch(),
action: action,
isPreview: isPreview,
isTerminal: isInteractive,
opts: opts,
renderer: renderer,
stack: stack,
proj: proj,
eventUrnToResourceRow: make(map[resource.URN]ResourceRow),
suffixColumn: int(statusColumn),
suffixesArray: []string{"", ".", "..", "..."},
urnToID: make(map[resource.URN]string),
displayOrderCounter: 1,
opStopwatch: newOpStopwatch(),
}

ticker := time.NewTicker(1 * time.Second)
Expand All @@ -289,27 +283,7 @@ func ShowProgressEvents(op string, action apitype.UpdateKind, stack tokens.Name,
}

func (display *ProgressDisplay) println(line string) {
display.renderer.println(display, display.opts.Color.Colorize(line))
}

func (display *ProgressDisplay) uncolorizeString(v string) string {
uncolorized, has := display.colorizedToUncolorized[v]
if !has {
uncolorized = colors.Never.Colorize(v)
display.colorizedToUncolorized[v] = uncolorized
}

return uncolorized
}

func (display *ProgressDisplay) uncolorizeColumns(columns []string) []string {
uncolorizedColumns := make([]string, len(columns))

for i, v := range columns {
uncolorizedColumns[i] = display.uncolorizeString(v)
}

return uncolorizedColumns
display.renderer.println(display, line)
}

type treeNode struct {
Expand Down Expand Up @@ -415,10 +389,9 @@ func (display *ProgressDisplay) convertNodesToRows(
}

colorizedColumns := make([]string, len(node.colorizedColumns))
uncolorisedColumns := display.uncolorizeColumns(node.colorizedColumns)

for i, colorizedColumn := range node.colorizedColumns {
columnWidth := utf8.RuneCountInString(uncolorisedColumns[i])
columnWidth := colors.MeasureColorizedString(colorizedColumn)

if i == display.suffixColumn {
columnWidth += maxSuffixLength
Expand Down
25 changes: 12 additions & 13 deletions pkg/backend/display/tableutil.go
Expand Up @@ -16,7 +16,6 @@ package display

import (
"strings"
"unicode/utf8"

"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
Expand All @@ -26,9 +25,9 @@ func columnHeader(msg string) string {
return colors.Underline + colors.BrightBlue + msg + colors.Reset
}

func messagePadding(message string, maxLength, extraPadding int) string {
extraWhitespace := maxLength - utf8.RuneCountInString(message)
contract.Assertf(extraWhitespace >= 0, "Neg whitespace. %v %s", maxLength, message)
func messagePadding(message string, maxWidth, extraPadding int) string {
extraWhitespace := maxWidth - colors.MeasureColorizedString(message)
contract.Assertf(extraWhitespace >= 0, "Neg whitespace. %v %s", maxWidth, message)

// Place two spaces between all columns (except after the first column). The first
// column already has a ": " so it doesn't need the extra space.
Expand All @@ -38,12 +37,12 @@ func messagePadding(message string, maxLength, extraPadding int) string {
}

// Gets the padding necessary to prepend to a column in order to keep it aligned in the terminal.
func columnPadding(uncolorizedColumns []string, columnIndex int, maxColumnLengths []int) string {
func columnPadding(columns []string, columnIndex int, maxColumnWidths []int) string {
extraWhitespace := " "
if columnIndex >= 0 && len(maxColumnLengths) > 0 {
column := uncolorizedColumns[columnIndex]
maxLength := maxColumnLengths[columnIndex]
extraWhitespace = messagePadding(column, maxLength, 2)
if columnIndex >= 0 && len(maxColumnWidths) > 0 {
column := columns[columnIndex]
maxWidth := maxColumnWidths[columnIndex]
extraWhitespace = messagePadding(column, maxWidth, 2)
}
return extraWhitespace
}
Expand All @@ -52,11 +51,11 @@ func columnPadding(uncolorizedColumns []string, columnIndex int, maxColumnLength
// status, then some amount of optional padding, then some amount of msgWithColors, then the
// suffix. Importantly, if there isn't enough room to display all of that on the terminal, then
// the msg will be truncated to try to make it fit.
func renderRow(colorizedColumns, uncolorizedColumns []string, maxColumnLengths []int) string {
func renderRow(columns []string, maxColumnWidths []int) string {
var row strings.Builder
for i := 0; i < len(colorizedColumns); i++ {
row.WriteString(columnPadding(uncolorizedColumns, i-1, maxColumnLengths))
row.WriteString(colorizedColumns[i])
for i := 0; i < len(columns); i++ {
row.WriteString(columnPadding(columns, i-1, maxColumnWidths))
row.WriteString(columns[i])
}
return row.String()
}

0 comments on commit 572912f

Please sign in to comment.