Releases: charmbracelet/lipgloss
v0.9.0
My, how the tables have turned
Now you can draw Table
s with Lip Gloss! ๐
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)
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
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:
- fix: border size calculation by @mieubrisse in #197
- fix: renderer race condition by @aymanbagabas in #210
- fix: cache color profile and background by @aymanbagabas in #212
Full Changelog: v0.7.1...v0.8.0
v0.7.1
This bugfix release fixes a problem introduced in v0.7.0 where applications could freeze or hang on start-up.
What's Changed
- fix(renderer): use termenv default renderer by @aymanbagabas in #179
- chore: bump termenv to v0.15.1 by @muesli in #180
Full Changelog: v0.7.0...v0.7.1
v0.7.0
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
- lipgloss renderer by @aymanbagabas in #140 and #174
- add BlockBorder, OuterHalfBlockBorder, and InnerHalfBlockBorder border styles by @VictorBersy in #120
Fixed
- RGBA implementations for non-hex color values by @muesli in #126
- unify get border size function names by @nerg4l in #148
- reduce dependencies by @caarlos0 in #146
- don't concurrently change output profiles by @muesli in #172
New Contributors
- @dependabot made their first contribution in #133
- @winder made their first contribution in #147
- @VictorBersy made their first contribution in #120
- @nervo made their first contribution in #156
- @caarlos0 made their first contribution in #146
- @isti115 made their first contribution in #170
- @nerg4l made their first contribution in #148
Full Changelog: v0.6.0...v0.7.0
v0.6.0
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!")
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
- Non-Interpolated Colors by @meowgorithm in #100
- Vertical Alignment by @maaslalani in #106
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
- @Evertras made their first contribution in #71
- @ismaelpadilla made their first contribution in #94
- @mark2185 made their first contribution in #103
- @inkel made their first contribution in #107
Full Changelog: v0.5.0...v0.6.0
Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Slack.
v0.5.0
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 withSetString()
(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
- @maaslalani made their first contribution in #48
- @stefanvanburen made their first contribution in #51
- @ryantriangles made their first contribution in #49
- @76creates made their first contribution in #66
Full Changelog: v0.4.0...v0.5.0
Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Slack.
v0.4.0
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)
- Borders:
- 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.
v0.3.0
Utility Functions
This release adds two utility functions to the Lip Gloss tool belt:
-
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. -
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 stringSetColorProfile
: set the color profile on a package-wide context
Changed
- Bump
go-runewidth
to v0.0.13 for improved emoji rendering
Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse or right here in GitHub Discussions.
v0.2.1
Border Fantasy
This PR adds support for fancier borders, fixes some bugs, and adds a helper function for measuring text blocks.
With the new border support, it's possible to construct borders from multiple runes, such as this:
New
- Support for multi-rune borders
- Added
Size() (int, int)
for returning the width and the height of a block in one go
Fixed
- Bump go-runewidth to fix some emoji mis-measuring
- Fix a panic that could happen in custom borders
Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse or right here in GitHub Discussions.
v0.2.0
Getters
This PR adds getters for all style rules, enabling you to query your style rules. This can be handy when building layouts, particularly when styles are variable, such as a component. For example:
if headerStyle.GetMarginLeft() > lipgloss.Width(spinner) + lipgloss.Width(gap) {
// jam the spinner in the left gutter
} else {
// just put the spinner on the right
}
For details on the getter API, check out the docs.
Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse or right here in GitHub Discussions.