-
Notifications
You must be signed in to change notification settings - Fork 252
docs: add v2 upgrade guide + release notes #509
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
aymanbagabas
wants to merge
1
commit into
v2-exp
Choose a base branch
from
charm-1225-whats-new-and-upgrade-guide
base: v2-exp
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,279 @@ | ||||||
| # Glamour v2 Upgrade Guide | ||||||
|
|
||||||
| This guide will help you migrate from Glamour v1 to v2. Most upgrades are straightforward and can be completed in minutes. | ||||||
|
|
||||||
| ## Update Import Paths | ||||||
|
|
||||||
| **Required:** All imports must use the new `charm.land` module path with `/v2`: | ||||||
|
|
||||||
| ```diff | ||||||
| -import "github.com/charmbracelet/glamour" | ||||||
| -import "github.com/charmbracelet/glamour/ansi" | ||||||
| -import "github.com/charmbracelet/glamour/styles" | ||||||
| +import "charm.land/glamour/v2" | ||||||
| +import "charm.land/glamour/v2/ansi" | ||||||
| +import "charm.land/glamour/v2/styles" | ||||||
| ``` | ||||||
|
|
||||||
| ## Update Dependencies | ||||||
|
|
||||||
| ```bash | ||||||
| go get charm.land/glamour/v2 | ||||||
| ``` | ||||||
|
|
||||||
| If you need color downsampling (most apps do): | ||||||
|
|
||||||
| ```bash | ||||||
| go get charm.land/lipgloss/v2 | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| ``` | ||||||
|
|
||||||
| ## Remove Auto Style Detection | ||||||
|
|
||||||
| **Breaking:** `WithAutoStyle()` has been removed. The default style is now `"dark"`. | ||||||
|
|
||||||
| ```diff | ||||||
| -r, _ := glamour.NewTermRenderer( | ||||||
| - glamour.WithAutoStyle(), | ||||||
| -) | ||||||
| +r, _ := glamour.NewTermRenderer( | ||||||
| + // "dark" is the default, or specify explicitly | ||||||
| + glamour.WithStylePath("dark"), | ||||||
| +) | ||||||
| ``` | ||||||
|
|
||||||
| If you were relying on automatic style selection based on terminal background, you'll need to choose the style explicitly: | ||||||
|
|
||||||
| ```go | ||||||
| // For light backgrounds | ||||||
| r, _ := glamour.NewTermRenderer(glamour.WithStylePath("light")) | ||||||
|
|
||||||
| // For dark backgrounds (default) | ||||||
| r, _ := glamour.NewTermRenderer(glamour.WithStylePath("dark")) | ||||||
|
|
||||||
| // Other built-in styles: "pink", "dracula", "tokyo-night", "ascii" | ||||||
| r, _ := glamour.NewTermRenderer(glamour.WithStylePath("dracula")) | ||||||
| ``` | ||||||
|
|
||||||
| Want to detect the terminal background yourself? You can use Lip Gloss: | ||||||
|
|
||||||
| ```go | ||||||
| import "charm.land/lipgloss/v2" | ||||||
|
|
||||||
| // Detect if we're on a dark background | ||||||
| isDark := lipgloss.HasDarkBackground() | ||||||
|
|
||||||
| style := "dark" | ||||||
| if !isDark { | ||||||
| style = "light" | ||||||
| } | ||||||
|
|
||||||
| r, _ := glamour.NewTermRenderer(glamour.WithStylePath(style)) | ||||||
| ``` | ||||||
|
|
||||||
| ## Handle Color Downsampling Explicitly | ||||||
|
|
||||||
| **Breaking:** `WithColorProfile()` has been removed. Use Lip Gloss for color adaptation: | ||||||
|
|
||||||
| ```diff | ||||||
| -import "github.com/muesli/termenv" | ||||||
| - | ||||||
| -r, _ := glamour.NewTermRenderer( | ||||||
| - glamour.WithColorProfile(termenv.TrueColor), | ||||||
| -) | ||||||
| -out, _ := r.Render(markdown) | ||||||
| -fmt.Print(out) | ||||||
| +import "charm.land/lipgloss/v2" | ||||||
| + | ||||||
| +r, _ := glamour.NewTermRenderer( | ||||||
| + glamour.WithWordWrap(80), | ||||||
| +) | ||||||
| +out, _ := r.Render(markdown) | ||||||
| + | ||||||
| +// Lip Gloss handles color downsampling based on terminal capabilities | ||||||
| +lipgloss.Print(out) | ||||||
| ``` | ||||||
|
|
||||||
| Why the change? Glamour is now pure — it always produces the same output for the same input. This makes it more predictable and testable. Lip Gloss handles the terminal-specific color adaptation when you're ready to display the output. | ||||||
|
|
||||||
| If you don't need color adaptation (e.g., you know you're always outputting TrueColor): | ||||||
|
|
||||||
| ```go | ||||||
| r, _ := glamour.NewTermRenderer(glamour.WithWordWrap(80)) | ||||||
| out, _ := r.Render(markdown) | ||||||
| fmt.Print(out) // Direct output, no downsampling | ||||||
| ``` | ||||||
|
|
||||||
| ## Remove Overline Styles | ||||||
|
|
||||||
| **Breaking:** The `Overlined` field has been removed from style configurations. | ||||||
|
|
||||||
| If you have custom styles using `Overlined`: | ||||||
|
|
||||||
| ```diff | ||||||
| StylePrimitive: ansi.StylePrimitive{ | ||||||
| Bold: &trueBool, | ||||||
| Underline: &trueBool, | ||||||
| - Overlined: &trueBool, | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| Overline was rarely supported across terminals and not widely used. If you need similar visual separation, consider alternatives like underline, bold, inverse, or background colors. | ||||||
|
|
||||||
| ## Update Custom Style Definitions | ||||||
|
|
||||||
| If you maintain custom `StyleConfig` definitions, update the import paths: | ||||||
|
|
||||||
| ```diff | ||||||
| -import "github.com/charmbracelet/glamour/ansi" | ||||||
| +import "charm.land/glamour/v2/ansi" | ||||||
|
|
||||||
| var myStyle = &ansi.StyleConfig{ | ||||||
| // Your custom style definition | ||||||
| Document: ansi.StyleBlock{ | ||||||
| StylePrimitive: ansi.StylePrimitive{ | ||||||
| Color: stringPtr("#E6DB74"), | ||||||
| }, | ||||||
| }, | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| The structure is the same; only the import path changes. | ||||||
|
|
||||||
| ## Verify Custom Writers (Advanced) | ||||||
|
|
||||||
| If you implemented custom margin or padding writers using `ansi.MarginWriter`: | ||||||
|
|
||||||
| 1. Ensure you call `.Close()` on all writer instances | ||||||
| 2. The new `IndentWriter` and `PaddingWriter` types are available for custom use | ||||||
|
|
||||||
| ```go | ||||||
| import "charm.land/glamour/v2/ansi" | ||||||
|
|
||||||
| mw := ansi.NewMarginWriter(ctx, w, style) | ||||||
| defer mw.Close() // Important: always close writers now | ||||||
|
|
||||||
| // Write your content | ||||||
| io.WriteString(mw, content) | ||||||
| ``` | ||||||
|
|
||||||
| This improves memory management and prevents resource leaks. | ||||||
|
|
||||||
| ## Example Migration | ||||||
|
|
||||||
| Here's a complete before/after example: | ||||||
|
|
||||||
| ### Before (v1) | ||||||
|
|
||||||
| ```go | ||||||
| package main | ||||||
|
|
||||||
| import ( | ||||||
| "fmt" | ||||||
| "github.com/charmbracelet/glamour" | ||||||
| "github.com/muesli/termenv" | ||||||
| ) | ||||||
|
|
||||||
| func main() { | ||||||
| md := `# Hello World | ||||||
|
|
||||||
| This is **Glamour v1**! | ||||||
| ` | ||||||
|
|
||||||
| r, _ := glamour.NewTermRenderer( | ||||||
| glamour.WithAutoStyle(), | ||||||
| glamour.WithColorProfile(termenv.TrueColor), | ||||||
| glamour.WithWordWrap(80), | ||||||
| ) | ||||||
|
|
||||||
| out, _ := r.Render(md) | ||||||
| fmt.Print(out) | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| ### After (v2) | ||||||
|
|
||||||
| ```go | ||||||
| package main | ||||||
|
|
||||||
| import ( | ||||||
| "fmt" | ||||||
| "charm.land/glamour/v2" | ||||||
| "charm.land/lipgloss/v2" | ||||||
| ) | ||||||
|
|
||||||
| func main() { | ||||||
| md := `# Hello World | ||||||
|
|
||||||
| This is **Glamour v2**! | ||||||
| ` | ||||||
|
|
||||||
| r, _ := glamour.NewTermRenderer( | ||||||
| glamour.WithStylePath("dark"), // or omit for default | ||||||
| glamour.WithWordWrap(80), | ||||||
| ) | ||||||
|
|
||||||
| out, _ := r.Render(md) | ||||||
| lipgloss.Print(out) // Handles color downsampling | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| ## Testing Your Migration | ||||||
|
|
||||||
| After making changes: | ||||||
|
|
||||||
| 1. **Run your tests** — Ensure all tests pass with the new version | ||||||
| 2. **Visual check** — Render sample markdown and verify output looks correct | ||||||
| 3. **Check wrapping** — Pay special attention to text wrapping if you have CJK or emoji content (it should be better now!) | ||||||
| 4. **Test hyperlinks** — If you use autolinks, verify they render correctly | ||||||
|
|
||||||
| ## Common Issues | ||||||
|
|
||||||
| ### "cannot find package" | ||||||
|
|
||||||
| Make sure you've updated your `go.mod`: | ||||||
|
|
||||||
| ```bash | ||||||
| go get charm.land/glamour/v2 | ||||||
| ``` | ||||||
|
|
||||||
| And that all imports use the new path with `/v2`. | ||||||
|
|
||||||
| ### Colors look wrong | ||||||
|
|
||||||
| If colors aren't displaying correctly, make sure you're using `lipgloss.Print()` instead of `fmt.Print()`: | ||||||
|
|
||||||
| ```go | ||||||
| out, _ := r.Render(markdown) | ||||||
| lipgloss.Print(out) // Not fmt.Print(out) | ||||||
| ``` | ||||||
|
|
||||||
| ### Text wrapping issues | ||||||
|
|
||||||
| Glamour v2 has improved text wrapping, especially for CJK characters and emojis. If you're seeing wrapping issues, it's likely a regression. Please [open an issue](https://github.com/charmbracelet/glamour/issues)! | ||||||
|
|
||||||
| ## Need Help? | ||||||
|
|
||||||
| If you run into issues during migration: | ||||||
|
|
||||||
| - Check the [examples directory](https://github.com/charmbracelet/glamour/tree/main/examples) for working code | ||||||
| - Review [What's New](WHATS_NEW.md) for detailed feature changes | ||||||
| - Join us on [Discord](https://charm.sh/chat) | ||||||
| - Open an issue on [GitHub](https://github.com/charmbracelet/glamour/issues) | ||||||
|
|
||||||
| ## Feedback | ||||||
|
|
||||||
| Migrated successfully? Having trouble? We'd love to hear about it! | ||||||
|
|
||||||
| - [Discord](https://charm.sh/chat) | ||||||
| - [The Fediverse](https://mastodon.social/@charmcli) | ||||||
| - [Twitter](https://twitter.com/charmcli) | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| Welcome to Glamour v2! 💄 | ||||||
|
|
||||||
| Part of [Charm](https://charm.sh). | ||||||
|
|
||||||
| <a href="https://charm.sh/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-badge.jpg" width="400"></a> | ||||||
|
|
||||||
| Charm热爱开源 • Charm loves open source | ||||||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.