diff --git a/src/config/segment_types.go b/src/config/segment_types.go index 752420c8c995..971253913a21 100644 --- a/src/config/segment_types.go +++ b/src/config/segment_types.go @@ -128,6 +128,8 @@ const ( NPM SegmentType = "npm" // NX writes which Nx version us currently active NX SegmentType = "nx" + // NIX writes the active nix shell details + NixShell SegmentType = "nix_shell" // OCAML writes the active Ocaml version OCAML SegmentType = "ocaml" // OS write os specific icon @@ -266,6 +268,7 @@ var Segments = map[SegmentType]func() SegmentWriter{ NIGHTSCOUT: func() SegmentWriter { return &segments.Nightscout{} }, NODE: func() SegmentWriter { return &segments.Node{} }, NPM: func() SegmentWriter { return &segments.Npm{} }, + NixShell: func() SegmentWriter { return &segments.NixShell{} }, NX: func() SegmentWriter { return &segments.Nx{} }, OCAML: func() SegmentWriter { return &segments.OCaml{} }, OS: func() SegmentWriter { return &segments.Os{} }, diff --git a/src/segments/nixshell.go b/src/segments/nixshell.go new file mode 100644 index 000000000000..dda5a09cba0e --- /dev/null +++ b/src/segments/nixshell.go @@ -0,0 +1,67 @@ +package segments + +import ( + "path/filepath" + "strings" + + "github.com/jandedobbeleer/oh-my-posh/src/properties" + "github.com/jandedobbeleer/oh-my-posh/src/runtime" +) + +type NixShellType string + +const ( + PURE NixShellType = "pure" + IMPURE NixShellType = "impure" + UNKNOWN NixShellType = "unknown" + NONE NixShellType = "none" +) + +type NixShell struct { + props properties.Properties + env runtime.Environment + + ShellType string +} + +func (n *NixShell) Template() string { + return "via {{ .ShellType }}-shell" +} + +func (n *NixShell) DetectShellType() NixShellType { + switch n.env.Getenv("IN_NIX_SHELL") { + case "pure": + return PURE + case "impure": + return IMPURE + default: + if n.InNewNixShell() { + return UNKNOWN + } + return NONE + } +} + +// Hack to detect if we're in a `nix shell` (in contrast to a `nix-shell`). +func (n *NixShell) InNewNixShell() bool { + paths := filepath.SplitList(n.env.Getenv("PATH")) + + for _, p := range paths { + if strings.Contains(p, "/nix/store") { + return true + } + } + + return false +} + +func (n *NixShell) Init(props properties.Properties, env runtime.Environment) { + n.props = props + n.env = env + + n.ShellType = string(n.DetectShellType()) +} + +func (n *NixShell) Enabled() bool { + return n.ShellType != string(NONE) +} diff --git a/src/segments/nixshell_test.go b/src/segments/nixshell_test.go new file mode 100644 index 000000000000..e4547354084d --- /dev/null +++ b/src/segments/nixshell_test.go @@ -0,0 +1,76 @@ +package segments + +import ( + "fmt" + "testing" + + "github.com/alecthomas/assert" + "github.com/jandedobbeleer/oh-my-posh/src/properties" + "github.com/jandedobbeleer/oh-my-posh/src/runtime/mock" +) + +const ( + nixPath = "/nix/store/zznw8fnzss1vaqfg5hmv3y79s3hkqczi-devshell-dir/bin" + defaultPath = "/users/xyz/testing" + fullNixPath = defaultPath + ":" + nixPath +) + +func setupMockEnvironment(shellType string) *mock.Environment { + env := new(mock.Environment) + env.On("Getenv", "IN_NIX_SHELL").Return(shellType) + path := defaultPath + if shellType != "" { + path = fullNixPath + } + env.On("Getenv", "PATH").Return(path) + return env +} + +func TestNixShellSegment(t *testing.T) { + cases := []struct { + name string + expectedString string + shellType string + enabled bool + }{ + { + name: "Pure Nix Shell", + expectedString: "via pure-shell", + shellType: "pure", + enabled: true, + }, + { + name: "Impure Nix Shell", + expectedString: "via impure-shell", + shellType: "impure", + enabled: true, + }, + { + name: "Unknown Nix Shell", + expectedString: "via unknown-shell", + shellType: "unknown", + enabled: true, + }, + { + name: "No Nix Shell", + expectedString: "", + shellType: "", + enabled: false, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + env := setupMockEnvironment(tc.shellType) + n := NixShell{} + n.Init(properties.Map{}, env) + + if tc.enabled { + assert.True(t, n.Enabled(), fmt.Sprintf("Failed in case: %s", tc.name)) + assert.Equal(t, tc.expectedString, renderTemplate(env, n.Template(), n), tc.name) + } else { + assert.False(t, n.Enabled()) + } + }) + } +} diff --git a/themes/schema.json b/themes/schema.json index dac6b65038c2..b33d0b4e5d7e 100644 --- a/themes/schema.json +++ b/themes/schema.json @@ -4723,6 +4723,31 @@ } } } + }, + { + "if": { + "properties": { + "type": { + "const": "nix_shell" + } + } + }, + "then": { + "title": "Nix Shell Segment", + "description": "https://ohmyposh.dev/docs/segments/nix-shell", + "properties": { + "properties": { + "properties": { + "newprop": { + "type": "string", + "title": "New Property", + "description": "the default text to display", + "default": "Hello" + } + } + } + } + } } ] } diff --git a/website/docs/segments/cli/nix-shell.mdx b/website/docs/segments/cli/nix-shell.mdx new file mode 100644 index 000000000000..43746687040e --- /dev/null +++ b/website/docs/segments/cli/nix-shell.mdx @@ -0,0 +1,39 @@ +--- +id: nix-shell +title: Nix Shell +sidebar_label: Nix Shell +--- + +## What + +Display the [nix shell](https://nixos.org/guides/nix-pills/developing-with-nix-shell.html) status if inside a nix-shell environment. + +## Sample Configuration + +import Config from "@site/src/components/Config.js"; + + + +## Template ([info][templates]) + +:::note default template + +```template +via {{ .ShellType }}-shell" +``` + +::: + +### Properties + +| Name | Type | Description | +| ------------ | -------- | ----------------------------------------------------------- | +| `.ShellType` | `string` | the type of nix shell, can be `pure`, `impure` or `unknown` | diff --git a/website/sidebars.js b/website/sidebars.js index 9acb6258e2c3..1a1fbc6668dd 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -71,6 +71,7 @@ module.exports = { "segments/cli/kubectl", "segments/cli/mvn", "segments/cli/nbgv", + "segments/cli/nix-shell", "segments/cli/npm", "segments/cli/nx", "segments/cli/pnpm",