-
Notifications
You must be signed in to change notification settings - Fork 102
docs: add truecolor info #273
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
bashbunni
wants to merge
5
commits into
main
Choose a base branch
from
docs/truecolor
base: main
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
Show all changes
5 commits
Select commit
Hold shift + click to select a range
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
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,33 @@ | ||
| # Wish Docs | ||
|
|
||
| Welcome to the Wish official documentation. If you're new to the project, make | ||
| sure you check out the [README][README] for a high-level overview of the project | ||
| and how to get started. From there, take a look at the [examples][examples]. | ||
| They're ordered by complexity and will show you how to use Wish. If you're | ||
| looking for additional functionality not shown in the examples, I'd highly | ||
| recommend checking out the [godoc][pkg.go.dev]. The godoc showcases all of the | ||
| functionality available to you with Wish alongside descriptions on what those | ||
| functions do. | ||
|
|
||
| If you want *more* examples from projects of various sizes, | ||
| [sourcegraph][sourcegraph] is a great code search tool that can help you find | ||
| other projects that use Wish. A great way to leverage this tool is when looking | ||
| at our API (in the godoc), do a global search for that specific function. e.g. | ||
| `wish.NewServer`. If you have questions about the limitations of Wish, we're | ||
| happy to help, though given we're a small team of maintainers, it may take some | ||
| time. In the meantime, you may find that [phorm.ai][phorm] is helpful in | ||
| answering your questions about Charm projects. We've found it to be quite | ||
| helpful so far. | ||
|
|
||
| This directory includes additional information about how Wish works. The topics | ||
| chosen for this section are based on frequently asked questions in the | ||
| community. If there's a topic you'd like to see covered in this section, please | ||
| submit an [issue][issue] with links to or quotes of questions on that topic. | ||
| That will allow us to ensure we're answering the question effectively. | ||
|
|
||
| [README]: https://github.com/charmbracelet/wish?tab=readme-ov-file#wish | ||
| [examples]: https://github.com/charmbracelet/wish/tree/main/examples#wish-examples | ||
| [pkg.go.dev]:https://pkg.go.dev/github.com/charmbracelet/wish | ||
| [issue]: https://github.com/charmbracelet/wish/issues/new/choose | ||
| [phorm]: https://www.phorm.ai | ||
| [sourcegraph]: https://sourcegraph.com/search?q=context:global+wish.NewServer&patternType=keyword&sm=0 |
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,164 @@ | ||
| # Truecolor Over SSH With Wish | ||
|
|
||
| If you're having issues with colors displaying properly in your Wish apps, you | ||
| may have to force `truecolor` support with | ||
| `bm.MiddlewareWithColorProfile(handler, termenv.TrueColor)` when defining the | ||
| middleware for your `Wish` server. This will force `truecolor` support. For | ||
| example: | ||
|
|
||
| ```go | ||
| import ( | ||
| // ... | ||
| tea "github.com/charmbracelet/bubbletea" | ||
| "github.com/charmbracelet/lipgloss" | ||
| "github.com/charmbracelet/log" | ||
| "github.com/charmbracelet/ssh" | ||
| "github.com/charmbracelet/wish" | ||
| "github.com/charmbracelet/wish/activeterm" | ||
| "github.com/charmbracelet/wish/bubbletea" | ||
| "github.com/charmbracelet/wish/logging" | ||
| ) | ||
|
|
||
| // ... | ||
|
|
||
| func main() { | ||
| s, err := wish.NewServer( | ||
| wish.WithAddress(net.JoinHostPort(host, port)), | ||
| wish.WithHostKeyPath(".ssh/id_ed25519"), | ||
| wish.WithMiddleware( | ||
| bubbletea.MiddlewareWithColorProfile(teaHandler, termenv.TrueColor) // Force truecolor. | ||
| activeterm.Middleware(), // Bubble Tea apps usually require a PTY. | ||
| logging.Middleware(), | ||
| ), | ||
| )), | ||
| ) | ||
| // ... | ||
| ``` | ||
|
|
||
| [see more][examples-bubbletea] | ||
|
|
||
| This _may_ cause issues for users accessing your Wish app through a terminal | ||
| emulator that is not `truecolor` compatible (e.g. Apple's Terminal app). | ||
|
|
||
| ## Lipgloss Renderer aka "no colors when run in a server" | ||
|
|
||
| [Lipgloss][], which we use to create styles, will have its "runtime renderer", | ||
| which is based on the current system environment. | ||
|
|
||
| This is perfectly fine for CLI apps running locally. | ||
|
|
||
| On the case of Wish apps, though, the runtime is the server, but we want the | ||
| profile to match the one of the client. | ||
|
|
||
| To do this, we can a create a custom renderer from the session, and use it to | ||
| create styles, for example: | ||
|
|
||
| ```go | ||
| import ( | ||
| // ... | ||
| "github.com/charmbracelet/lipgloss" | ||
| "github.com/charmbracelet/wish/bubbletea" | ||
| ) | ||
|
|
||
| // ... | ||
|
|
||
| func teaHandler(s ssh.Session) (tea.Model, []tea.ProgramOption) { | ||
| renderer := bubbletea.MakeRenderer(s) | ||
|
|
||
| // ... | ||
|
|
||
| m := &model{} | ||
| m.initStyles(renderer) | ||
| return m, nil | ||
| } | ||
|
|
||
| func (m *model) initStyles(r *lipgloss.Renderer) { | ||
| m.txtStyle = r.NewStyle().Foreground(lipgloss.Color("10")) | ||
| } | ||
| ``` | ||
|
|
||
| This is one strategy you can use, but you can adapt it to whatever makes more | ||
| sense for your app. | ||
|
|
||
| ## Color profiles? What, like it's hard? | ||
|
|
||
| We'll dive into the root of the problem for those who want to learn more. In an | ||
| SSH session, the client only sends the `TERM` environment variable, which can | ||
| only detect `256 color` support. If you run `echo $COLORTERM` in your shell | ||
| you'll likely see `truecolor` as the result, which is what you want for ultra | ||
| colorful terminal outputs. If you don't see that as a result, it might be time | ||
| to try a new [terminal emulator][supported-emulators]. | ||
|
|
||
| Unfortunately, there is no standard way for terminals to detect `truecolor` | ||
| support in an SSH session, hence why it defaults to `256 color`. Most terminals | ||
| express their `truecolor` support with the `COLORTERM` environment variable, | ||
| but this doesn't get sent when connecting over SSH. One workaround is to make | ||
| SSH send this environment variable using `SendEnv COLORTERM` in the [`ssh | ||
| config`][truecolor-ssh]. By default, the OpenSSH client (what you're using when | ||
| you run `ssh`) will only send the `TERM` to the remote, so other variables must | ||
| be configured. In the future, we hope to solve this problem by querying the | ||
| terminal for support if `COLORTERM` is not detected. | ||
|
|
||
| You can learn more about [checking for `COLORTERM`][colorterm-issue]. | ||
|
|
||
| Because of this, the color options are limited and your experience running the | ||
| app locally will differ to how it presents over SSH. You're probably wondering | ||
| _how much_ of a difference this makes. Well, `256 color` support uses a palette | ||
| with 256 colors available. By contrast, `truecolor` supports a whopping 16 | ||
| **million** different colors. | ||
|
|
||
| [Learn more about color standards for terminal emulators][termstandard] | ||
|
|
||
| ## What is Wish | ||
|
|
||
| Wish is an SSH server that allows you to make your apps accessible over SSH. It | ||
| uses SSH middleware to handle connections, so you can serve specific actions to | ||
| the user, then call the next middleware. | ||
|
|
||
| Wish uses the SSH protocol to authenticate users, then allows the developer to | ||
| specify how to handle these connections. We've used Wish to serve both TUIs | ||
| (textual UIs) _and_ CLIs. If you've hosted your own [Soft Serve][soft] git | ||
| server, then you'll have seen this first hand. Soft Serve uses a middleware to | ||
| serve the TUI and another middleware for its CLI, allowing users to interact | ||
| with the server through either interface. In this case, the CLI is useful for | ||
| any server administration tasks, while the TUI provides a great interface to | ||
| view your repositories. Note that both of these options are accessible through | ||
| the same port (pretty neat). | ||
|
|
||
| Similar to a website, this process runs on the server, freeing up your computer's | ||
| resources for other things. What's great about this is it also gives you a | ||
| consistent state no matter where you connect from (as long as you've got your | ||
| authorized SSH keys with you). | ||
|
|
||
| ## Noteworthy environment variables (for debugging) | ||
|
|
||
| These environment variables may help you should you encounter unexpected | ||
| behavior when working with terminal styling. | ||
|
|
||
| `TERM` - provides information about your terminal emulator's capabilities. This | ||
| is the only environment variable out of this list that is sent in an SSH | ||
| session. The rest are included for debugging purposes only. | ||
|
|
||
| `COLORTERM` - provides information about your terminal emulator's color | ||
| capabilities. Used primarily to specify if your emulator has `truecolor` | ||
| support. | ||
|
|
||
| `NO_COLOR` - turns colors on and off. `NO_COLOR=1` for non-colored text | ||
| outputs, `NO_COLOR=0` for colored text outputs. | ||
|
|
||
| `CLICOLOR` - turns colors on and off. `CLICOLOR=1` for colored text outputs, | ||
| `CLICOLOR=0` for non-colored text outputs. | ||
|
|
||
| `CLICOLOR_FORCE` - overrides `CLICOLOR`. | ||
|
|
||
| `NO_COLOR` vs `CLICOLOR`: if `NO_COLOR` is set or `CLICOLOR=0` then the output should | ||
| not be colored. Otherwise, the output can include ansi sequences. | ||
|
|
||
| [termstandard]: https://github.com/termstandard/colors | ||
| [supported-emulators]: https://github.com/termstandard/colors?tab=readme-ov-file#terminal-emulators | ||
| [truecolor-ssh]: https://fixnum.org/2023-03-22-helix-truecolor-ssh-screen/ | ||
| [colorterm-issue]: https://github.com/termstandard/colors?tab=readme-ov-file#truecolor-detection | ||
| [examples-bubbletea]: https://github.com/charmbracelet/wish/blob/main/examples/bubbletea/main.go#L35 | ||
| [soft]: https://github.com/charmbracelet/soft-serve | ||
| [termenv]: https://github.com/muesli/termenv/blob/345783024a348cbb893bf6f08f1d7ab79d2e22ff/termenv_unix.go#L53 | ||
| [lipgloss]: https://github.com/charmbracelet/lipgloss |
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.
fwiw, we maintain our own fork of gliderlabs/ssh and this library only provides abstractions on top of Golang's SSH implementation