Skip to content

Releases: charmbracelet/lipgloss

v0.10.0

05 Mar 15:57
v0.10.0
439c06f
Compare
Choose a tag to compare

String Transforms 💄

Lip Gloss v0.10.0 features a brand new Transform function for Styles to alter strings at render time. As well as some bug fixes, like ANSI-aware table cell truncation. 🧹

Simply define a Transform function as func (string) string and apply it to any style:

// Example:
s := NewStyle().Transform(strings.ToUpper)
fmt.Println(s.Render("raow!") // "RAOW!"

Or, if you prefer:

// Example:
reverse := func(s string) string {
    n := 0
    rune := make([]rune, len(s))
    for _, r := range s {
        rune[n] = r
	n++
    }
    rune = rune[0:n]
    for i := 0; i < n/2; i++ {
        rune[i], rune[n-1-i] = rune[n-1-i], rune[i]
    }
    return string(rune)
}

s := NewStyle().Transform(reverse)
fmt.Println(s.Render("The quick brown 狐 jumped over the lazy 犬")
// "犬 yzal eht revo depmuj 狐 nworb kciuq ehT",

What's Changed?

New Contributors

Full Changelog: v0.9.1...v0.10.0


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Slack.

v0.9.1

12 Oct 05:14
v0.9.1
f093bc1
Compare
Choose a tag to compare

This bugfix release changes the Table Headers API to accept []string for consistency with Row / Rows and downgrades Lip Gloss to Go version v1.17.

What's Changed

Full Changelog: v0.9.0...v0.9.1

v0.9.0

10 Oct 15:33
v0.9.0
4476263
Compare
Choose a tag to compare

My, how the tables have turned

Now you can draw Tables with Lip Gloss! 💅

image

View the source code.

Let's get started

import "github.com/charmbracelet/lipgloss/table"

Define some rows of data.

rows := [][]string{
    {"Chinese", "您好", "你好"},
    {"Japanese", "こんにちは", "やあ"},
    {"Arabic", "أهلين", "أهلا"},
    {"Russian", "Здравствуйте", "Привет"},
    {"Spanish", "Hola", "¿Qué tal?"},
}

Use the table package to style and render the table.

t := table.New().
    Border(lipgloss.NormalBorder()).
    BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99"))).
    StyleFunc(func(row, col int) lipgloss.Style {
        switch {
        case row == 0:
            return HeaderStyle
        case row%2 == 0:
            return EvenRowStyle
        default:
            return OddRowStyle
        }
    }).
    Headers("LANGUAGE", "FORMAL", "INFORMAL").
    Rows(rows...)

// You can also add tables row-by-row
t.Row("English", "You look absolutely fabulous.", "How's it going?")

Print the table.

fmt.Println(t)
Table example

For more on tables see the examples.

Additional Borders

Lip Gloss' Border now supports additional middle border separators.

type Border struct {
    // ...
    MiddleLeft   string
    MiddleRight  string
    Middle       string
    MiddleTop    string
    MiddleBottom string
}

v0.8.0

22 Aug 18:36
07d2272
Compare
Choose a tag to compare

Predictable Tabs

At last: tabs that render the way you want ’em to. With the new Style.TabWidth() method, you can determine exactly how a \t will render.

Before this release, Lip Gloss used to mis-measure a tab (i.e. a \t) at 0 cells wide when they actually render at different widths in different terminals (usually 8 cells, sometimes 4 cells). For these reasons, tabs are almost never what you want when designing layouts for TUIs.

With this release, a tab will get converted to 4 spaces by default—so this is a behavioral change—but you can customize the behavior as well as disable it entirely.

s := lipgloss.NewStyle()        // 4 spaces per tab, the default
s = s.TabWidth(2)               // 2 spaces per tab
s = s.TabWidth(0)               // remove tabs
s = s.TabWidth(-1)              // don't convert tabs to spaces
s = s.TabWidth(NoTabConversion) // alias of the above

You can disable the feature with Style.TabWidth(NoTabConversion) (or Style.TabWidth(-1), if you're the pedantic type).

Bug Fixes

This release also includes a bunch of bug fixes. This includes:


Full Changelog: v0.7.1...v0.8.0

v0.7.1

09 Mar 19:14
Compare
Choose a tag to compare

This bugfix release fixes a problem introduced in v0.7.0 where applications could freeze or hang on start-up.

What's Changed

Full Changelog: v0.7.0...v0.7.1

v0.7.0

08 Mar 20:29
19ca9a3
Compare
Choose a tag to compare

Custom Renderers

We're pleased to introduce custom renders for Lip Gloss! Custom renderers allow you to render to a specific outputs, which is particularly important when you want to detect the color profile and dark background status for multiple different outputs at runtime, such as in a server-client situation.

Here's what it looks like:

func myLittleHandler(sess ssh.Session) {
    // Create a renderer for the client.
    renderer := lipgloss.NewRenderer(sess)

    // Create a new style on the renderer.
    style := renderer.NewStyle().Background(lipgloss.AdaptiveColor{Light: "63", Dark: "228"})

    // Render. The color profile and dark background state will be correctly detected.
    io.WriteString(sess, style.Render("Heyyyyyyy"))
}

For a full example on using a custom renderer over SSH with Wish see the SSH example.

New API Stuff

  • type Renderer struct
  • NewRenderer(io.Writer)
  • DefaultRenderer()
  • SetDefaultRenderer(*lipgloss.Renderer)
  • style.Renderer(*lipgloss.Renderer) Style

What's Changed

New

Fixed

New Contributors

Full Changelog: v0.6.0...v0.7.0

v0.6.0

06 Sep 18:36
Compare
Choose a tag to compare

Vertical Alignment & Per-Profile Color Settings

In this latest release of Lip Gloss, styles now support vertical alignment! Additionally, we introduced two new color types, CompleteColor and CompleteAdaptiveColor, which lets you bypass automatic color interpolation choose colors for each color profile (ANSI, ANSI256, and TrueColor).

Align content in a Style vertically at the top, center, or bottom. To get started make a style with some Height and an AlignVertical property.

lipgloss.NewStyle().Height(5).AlignVertical(lipgloss.Center).Render("Hello, Center!")

or use the Align shorthand which sets both horizontal and vertical alignments:

lipgloss.NewStyle().Height(5).Align(lipgloss.Left, lipgloss.Bottom).Render("Hello, Center!")

image

New API:

Note, there are no breaking changes since if the Align shorthand will still accept 1 argument (variadic arguments) and will set only the horizontal alignment to maintain original functionality

  • Align(p ...Position)
  • AlignVertical(p Position)
  • AlignHorizontal(p Position)
  • GetAlignVertical() Position
  • GetAlignHorizontal() Position

Complete Colors

This revision introduces two new color types CompleteColor and CompleteAdaptiveColor. Not for the faint of heart, these types are for bypassing automatic color interpolation so you can specify exact colors for all color profiles in cases where the interpolation can benefit from manual adjustment:

cc := CompleteColor{
	TrueColor: "#6B51FF",
	ANSI256: "63",
	ANSI: "5",
}

cac := CompleteAdaptiveColor{
	Light: CompleteColor{
		TrueColor: "#FF51CE",
		ANSI256: "213",
		ANSI: "5",
	},
	Dark: CompleteColor{
		TrueColor: "#6B51FF",
		ANSI256: "63",
		ANSI: "5",
	},
}

New

Fixed

  • Protect against concurrent color profile access with a sync.RWMutex by @meowgorithm in #68
  • don't overwrite background when inheriting by @76creates in #69

New Contributors

Full Changelog: v0.5.0...v0.6.0


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Slack.

v0.5.0

14 Feb 21:41
Compare
Choose a tag to compare

Laziness

Happy Valentines Day! Have you ever noticed that programming is the one field where laziness is totally awesome?

The big news in this release is that Lip Gloss will now wait until absolutely necessary to query for the terminal's background color. This was formerly a fairly heavy hit on the system, however it's been optimized to the point where we can now run it on demand. This, and some other major performance benefits, come from some acute improvements upstream in Termenv. For the low level details check out the release notes for the mighty Termenv v0.10.0 and v0.11.0 releases.

New

  • Styles now have a Value() method for getting the underlying string value set with SetString() (thanks @76creates) #66

Improved

  • Lazily detect the background color #61
  • Use termenv's EnvColorProfile, which respects NO_COLOR and CLICOLOR_FORCE env vars #64

Fixed

  • Fix JoinVertical behavior for non-edge non-center alignments (thanks @ryantriangles) #49

New Contributors

Full Changelog: v0.4.0...v0.5.0


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Slack.

v0.4.0

03 Sep 17:18
Compare
Choose a tag to compare

Quality-of-Life Updates

This release includes a menagerie of small but useful and handy improvements.

Automatic Wrapping for Long Words

Occasionally you’ll have a word (often a URL or a path) that runs wider than the Width() you set on a style:

// style.Width(5)
╭───────────╮
│Schnurrbart│
╰───────────╯
// ... that is definitely more than 5 cells wide

Such words will now automatically wrap:

// style.Width(5)
╭─────╮
│Schnu│
│rrbar│
│t    │
╰─────╯
// There we go

For details, see the corresponding PR.

Query Borders and Whitespace

Sometimes you need to measure borders and whitespace when calculating your layouts and you end up with code like this:

const horizontalPadding = 6

style.Copy().Width(windowWidth-horizontalPadding)

This update includes a multitude of methods for querying your styles so you can do away with unnecessary constants and magic numbers. For example:

style.Copy().Width(windowWidth-style.GetHorizontalPadding())

The most useful of these methods are perhaps the ones that let you query margins, borders and padding all at once:

  • Style.GetFrameSize() (x, y int)
  • Style.GetVerticalFrameSize() int
  • Style.GetHorizontalFrameSize() int

For details see the changelog below.

Improved Automatic Color Degradation

  • Better color conversions when automatically degrading a color profile (for example, when coercing from TrueColor to ANSI256).

The Mystical Hidden Border

At first glance a hidden border seems silly. Hidden borders can be useful, however, if you want to remove a border but maintain layout positioning in, say, an interactive TUI. Also note that you can still apply a background color to a hidden border.

To make a hidden border simply call lipgloss.HiddenBorder().


Changelog

Changed

  • Words wider than a style’s Width() now wrap automatically
  • Update termenv for improved color space for color profile conversions (it now uses the excellent HSLuv color space)

New

  • HiddenBorder(), which renders a border comprised of spaces
  • Style-level methods for querying borders and whitespace:
    • Borders:
      • Style.GetBorderTopSize() int
      • Style.GetBorderRightSize() int
      • Style.GetBorderBottomSize() int
      • Style.GetBorderLeftSize() int
      • Style.GetHorizontalBorderSize() int
      • Style.GetVerticalBorderSize() int
    • Margins:
      • Style.GetMarginTop() int
      • Style.GetMarginRight() int
      • Style.GetMarginBottom() int
      • Style.GetMarginLeft() int
      • Style.GetHorizontalMargins() int
      • Style.GetVerticalMargins() int
    • Padding:
      • Style.GetPaddingTop() int
      • Style.GetPaddingRight() int
      • Style.GetPaddingBottom() int
      • Style.GetPaddingLeft() int
      • Style.GetHorizontalPadding() int
      • Style.GetVerticalPadding() int
    • Get horizontal margins, padding, and border widths all at once:
      • Style.GetVerticalFrameSize() int
      • Style.GetHorizontalFrameSize() int
      • Style.GetFrameSize() (x, y int)
  • Border-level size querying methods:
    • Border.GetTopSize() int
    • Border.GetRightSize() int
    • Border.GetBottomSize() int
    • Border.GetLeftSize() int

Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse or right here in GitHub Discussions.

The Charm logo

v0.3.0

18 Jun 14:46
Compare
Choose a tag to compare

Utility Functions

This release adds two utility functions to the Lip Gloss tool belt:

  1. StyleRunes can apply styling to runes at specific indices in a string, perfect for highlighting matched characters in a fuzzy search result, marking a hotkey on a button and so on.

  2. SetColorProfile sets the color profile on a package-wide basis, which is very useful in testing. Note that outside of testing you probably don’t want to set the color profile as the best available option will be automatically chosen.

Changelog

New

  • StyleRunes: applying styling to specific runes in a string
  • SetColorProfile: set the color profile on a package-wide context

Changed


Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse or right here in GitHub Discussions.

The Charm logo