Repository: cli/cli
Pull request #10820 (2025-04-17 20:03:27)

Update configuration support for accessible colors
Fixes github/cli#857

- added support for `accessible_colors` configuration setting in `gh config` commandset
- updated default configuration file to contain `accessible_colors: disabled`
- add `GH_ACCESSIBLE_COLORS` env var to `gh environment`
- generated mocks via `go generate ./...` including previously missed prompter changes

### Acceptance Criteria

1. **When** user executes `gh config`
   **Then** new `accessible_colors` configuration setting is stated as taking `enabled` or `disabled` as values with default of `disabled`

   <img width="1512" alt="acceptance-criteria-1-gh-config" src="https://github.com/user-attachments/assets/f25b02a5-c277-4600-8c26-2e72b2256d1f" />

1. **Given** user executes `gh config set accessible_colors enabled`
   **When** user executes `gh config list`
   **Then** `accessible_colors=enabled` is presented

   <img width="1512" alt="acceptance-criteria-2-gh-config-list" src="https://github.com/user-attachments/assets/60aa6054-e03e-42dc-aa3b-4cff9c623c06" />

1. **Given** user executes `gh config set accessible_colors enabled`
   **And Given** user has color enabled
   **When** user executes `gh repo view andyfeller/markdown-lorem-ipsum`
   **Then** user can customize all colored text from rendered markdown through terminal preferences

   https://github.com/user-attachments/assets/e1a3ec40-b489-4d85-8d82-86c7ef695990

1. **Given** user executes `gh config set accessible_colors enabled`
   **And Given** user has color enabled
   **When** user executes `gh repo list`
   **Then** user can customize table header and date time columns through terminal preferences

   https://github.com/user-attachments/assets/d47f90d4-3b36-4807-a8c4-a582e428ed36

1. **Given** user executes `gh config set accessible_colors enabled`
   **And Given** user has color enabled
   **When** user executes `gh reference`
   **Then** user can customize command headers and content through terminal preferences

   https://github.com/user-attachments/assets/2d24ecfb-3b7c-46a2-88f0-98c0de0546ab

1. **Given** user has no GitHub CLI configuration file
   **When** user executes `gh` for the first time
   **Then** the default GitHub CLI configuration file includes `accessible_colors=disabled`

   <img width="1512" alt="acceptance-criteria-6-first-time" src="https://github.com/user-attachments/assets/427886ed-6ecf-4f4f-bb24-fe2b8b7b4192" />

1. **When** user executes `gh help environment`
   **Then** new `GH_ACCESSIBLE_COLORS` environment variable is presented

   <img width="1512" alt="acceptance-criteria-7-gh-environment" src="https://github.com/user-attachments/assets/628df8b6-fd0a-4203-b8f8-aff7d2c2722a" />



Patch:
diff --git a/go.mod b/go.mod
index 31b07f2cf..8fe69cc84 100644
--- a/go.mod
+++ b/go.mod
@@ -53,7 +53,7 @@ require (
 	golang.org/x/sync v0.13.0
 	golang.org/x/term v0.31.0
 	golang.org/x/text v0.24.0
-	google.golang.org/grpc v1.71.1
+	google.golang.org/grpc v1.71.0
 	google.golang.org/protobuf v1.36.6
 	gopkg.in/h2non/gock.v1 v1.1.2
 	gopkg.in/yaml.v3 v3.0.1
diff --git a/go.sum b/go.sum
index b312bcf6c..63a1cdd77 100644
--- a/go.sum
+++ b/go.sum
@@ -601,8 +601,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:
 google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
-google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
-google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
+google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
+google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
 google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/config/config.go b/internal/config/config.go
index e7534dfdb..c78dac15c 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -14,15 +14,18 @@ import (
 	ghConfig "github.com/cli/go-gh/v2/pkg/config"
 )
 
+// Important: some of the following configuration settings are used outside of `cli/cli`,
+// they are defined here to avoid `cli/cli` being changed unexpectedly.
 const (
+	accessibleColorsKey   = "accessible_colors" // used by cli/go-gh to enable the use of customizable, accessible 4-bit colors.
 	aliasesKey            = "aliases"
-	browserKey            = "browser"
+	browserKey            = "browser" // used by cli/go-gh to open URLs in web browsers
 	colorLabelsKey        = "color_labels"
-	editorKey             = "editor"
+	editorKey             = "editor" // used by cli/go-gh to open interactive text editor
 	gitProtocolKey        = "git_protocol"
-	hostsKey              = "hosts"
+	hostsKey              = "hosts" // used by cli/go-gh to locate authenticated host tokens
 	httpUnixSocketKey     = "http_unix_socket"
-	oauthTokenKey         = "oauth_token"
+	oauthTokenKey         = "oauth_token" // used by cli/go-gh to locate authenticated host tokens
 	pagerKey              = "pager"
 	promptKey             = "prompt"
 	preferEditorPromptKey = "prefer_editor_prompt"
@@ -109,6 +112,11 @@ func (c *cfg) Authentication() gh.AuthConfig {
 	return &AuthConfig{cfg: c.cfg}
 }
 
+func (c *cfg) AccessibleColors(hostname string) gh.ConfigEntry {
+	// Intentionally panic if there is no user provided value or default value (which would be a programmer error)
+	return c.GetOrDefault(hostname, accessibleColorsKey).Unwrap()
+}
+
 func (c *cfg) Browser(hostname string) gh.ConfigEntry {
 	// Intentionally panic if there is no user provided value or default value (which would be a programmer error)
 	return c.GetOrDefault(hostname, browserKey).Unwrap()
@@ -540,6 +548,8 @@ http_unix_socket:
 browser:
 # Whether to display labels using their RGB hex color codes in terminals that support truecolor. Supported values: enabled, disabled
 color_labels: disabled
+# Whether customizable, 4-bit accessible colors should be used. Supported values: enabled, disabled
+accessible_colors: disabled
 `
 
 type ConfigOption struct {
@@ -619,6 +629,15 @@ var Options = []ConfigOption{
 			return c.ColorLabels(hostname).Value
 		},
 	},
+	{
+		Key:           accessibleColorsKey,
+		Description:   "whether customizable, 4-bit accessible colors should be used",
+		DefaultValue:  "disabled",
+		AllowedValues: []string{"enabled", "disabled"},
+		CurrentValue: func(c gh.Config, hostname string) string {
+			return c.AccessibleColors(hostname).Value
+		},
+	},
 }
 
 func HomeDirPath(subdir string) (string, error) {
diff --git a/internal/config/stub.go b/internal/config/stub.go
index 78073da4a..8b9f14290 100644
--- a/internal/config/stub.go
+++ b/internal/config/stub.go
@@ -52,6 +52,9 @@ func NewFromString(cfgStr string) *ghmock.ConfigMock {
 			},
 		}
 	}
+	mock.AccessibleColorsFunc = func(hostname string) gh.ConfigEntry {
+		return cfg.AccessibleColors(hostname)
+	}
 	mock.BrowserFunc = func(hostname string) gh.ConfigEntry {
 		return cfg.Browser(hostname)
 	}
diff --git a/internal/gh/gh.go b/internal/gh/gh.go
index b17c6bd67..8f3e3cd5b 100644
--- a/internal/gh/gh.go
+++ b/internal/gh/gh.go
@@ -35,6 +35,8 @@ type Config interface {
 	// Set provides primitive access for setting configuration values, optionally scoped by host.
 	Set(hostname string, key string, value string)
 
+	// AccessibleColors returns the configured accessible_colors setting, optionally scoped by host.
+	AccessibleColors(hostname string) ConfigEntry
 	// Browser returns the configured browser, optionally scoped by host.
 	Browser(hostname string) ConfigEntry
 	// ColorLabels returns the configured color_label setting, optionally scoped by host.
diff --git a/internal/gh/mock/config.go b/internal/gh/mock/config.go
index b94cb084d..600eea5c1 100644
--- a/internal/gh/mock/config.go
+++ b/internal/gh/mock/config.go
@@ -19,6 +19,9 @@ var _ gh.Config = &ConfigMock{}
 //
 //		// make and configure a mocked gh.Config
 //		mockedConfig := &ConfigMock{
+//			AccessibleColorsFunc: func(hostname string) gh.ConfigEntry {
+//				panic("mock out the AccessibleColors method")
+//			},
 //			AliasesFunc: func() gh.AliasConfig {
 //				panic("mock out the Aliases method")
 //			},
@@ -74,6 +77,9 @@ var _ gh.Config = &ConfigMock{}
 //
 //	}
 type ConfigMock struct {
+	// AccessibleColorsFunc mocks the AccessibleColors method.
+	AccessibleColorsFunc func(hostname string) gh.ConfigEntry
+
 	// AliasesFunc mocks the Aliases method.
 	AliasesFunc func() gh.AliasConfig
 
@@ -124,6 +130,11 @@ type ConfigMock struct {
 
 	// calls tracks calls to the methods.
 	calls struct {
+		// AccessibleColors holds details about calls to the AccessibleColors method.
+		AccessibleColors []struct {
+			// Hostname is the hostname argument value.
+			Hostname string
+		}
 		// Aliases holds details about calls to the Aliases method.
 		Aliases []struct {
 		}
@@ -201,6 +212,7 @@ type ConfigMock struct {
 		Write []struct {
 		}
 	}
+	lockAccessibleColors   sync.RWMutex
 	lockAliases            sync.RWMutex
 	lockAuthentication     sync.RWMutex
 	lockBrowser            sync.RWMutex
@@ -219,6 +231,38 @@ type ConfigMock struct {
 	lockWrite              sync.RWMutex
 }
 
+// AccessibleColors calls AccessibleColorsFunc.
+func (mock *ConfigMock) AccessibleColors(hostname string) gh.ConfigEntry {
+	if mock.AccessibleColorsFunc == nil {
+		panic("ConfigMock.AccessibleColorsFunc: method is nil but Config.AccessibleColors was just called")
+	}
+	callInfo := struct {
+		Hostname string
+	}{
+		Hostname: hostname,
+	}
+	mock.lockAccessibleColors.Lock()
+	mock.calls.AccessibleColors = append(mock.calls.AccessibleColors, callInfo)
+	mock.lockAccessibleColors.Unlock()
+	return mock.AccessibleColorsFunc(hostname)
+}
+
+// AccessibleColorsCalls gets all the calls that were made to AccessibleColors.
+// Check the length with:
+//
+//	len(mockedConfig.AccessibleColorsCalls())
+func (mock *ConfigMock) AccessibleColorsCalls() []struct {
+	Hostname string
+} {
+	var calls []struct {
+		Hostname string
+	}
+	mock.lockAccessibleColors.RLock()
+	calls = mock.calls.AccessibleColors
+	mock.lockAccessibleColors.RUnlock()
+	return calls
+}
+
 // Aliases calls AliasesFunc.
 func (mock *ConfigMock) Aliases() gh.AliasConfig {
 	if mock.AliasesFunc == nil {
diff --git a/internal/prompter/prompter_mock.go b/internal/prompter/prompter_mock.go
index b817a491f..b15f8bf96 100644
--- a/internal/prompter/prompter_mock.go
+++ b/internal/prompter/prompter_mock.go
@@ -20,28 +20,28 @@ var _ Prompter = &PrompterMock{}
 //			AuthTokenFunc: func() (string, error) {
 //				panic("mock out the AuthToken method")
 //			},
-//			ConfirmFunc: func(s string, b bool) (bool, error) {
+//			ConfirmFunc: func(prompt string, defaultValue bool) (bool, error) {
 //				panic("mock out the Confirm method")
 //			},
-//			ConfirmDeletionFunc: func(s string) error {
+//			ConfirmDeletionFunc: func(requiredValue string) error {
 //				panic("mock out the ConfirmDeletion method")
 //			},
-//			InputFunc: func(s1 string, s2 string) (string, error) {
+//			InputFunc: func(prompt string, defaultValue string) (string, error) {
 //				panic("mock out the Input method")
 //			},
 //			InputHostnameFunc: func() (string, error) {
 //				panic("mock out the InputHostname method")
 //			},
-//			MarkdownEditorFunc: func(s1 string, s2 string, b bool) (string, error) {
+//			MarkdownEditorFunc: func(prompt string, defaultValue string, blankAllowed bool) (string, error) {
 //				panic("mock out the MarkdownEditor method")
 //			},
 //			MultiSelectFunc: func(prompt string, defaults []string, options []string) ([]int, error) {
 //				panic("mock out the MultiSelect method")
 //			},
-//			PasswordFunc: func(s string) (string, error) {
+//			PasswordFunc: func(prompt string) (string, error) {
 //				panic("mock out the Password method")
 //			},
-//			SelectFunc: func(s1 string, s2 string, strings []string) (int, error) {
+//			SelectFunc: func(prompt string, defaultValue string, options []string) (int, error) {
 //				panic("mock out the Select method")
 //			},
 //		}
@@ -55,28 +55,28 @@ type PrompterMock struct {
 	AuthTokenFunc func() (string, error)
 
 	// ConfirmFunc mocks the Confirm method.
-	ConfirmFunc func(s string, b bool) (bool, error)
+	ConfirmFunc func(prompt string, defaultValue bool) (bool, error)
 
 	// ConfirmDeletionFunc mocks the ConfirmDeletion method.
-	ConfirmDeletionFunc func(s string) error
+	ConfirmDeletionFunc func(requiredValue string) error
 
 	// InputFunc mocks the Input method.
-	InputFunc func(s1 string, s2 string) (string, error)
+	InputFunc func(prompt string, defaultValue string) (string, error)
 
 	// InputHostnameFunc mocks the InputHostname method.
 	InputHostnameFunc func() (string, error)
 
 	// MarkdownEditorFunc mocks the MarkdownEditor method.
-	MarkdownEditorFunc func(s1 string, s2 string, b bool) (string, error)
+	MarkdownEditorFunc func(prompt string, defaultValue string, blankAllowed bool) (string, error)
 
 	// MultiSelectFunc mocks the MultiSelect method.
 	MultiSelectFunc func(prompt string, defaults []string, options []string) ([]int, error)
 
 	// PasswordFunc mocks the Password method.
-	PasswordFunc func(s string) (string, error)
+	PasswordFunc func(prompt string) (string, error)
 
 	// SelectFunc mocks the Select method.
-	SelectFunc func(s1 string, s2 string, strings []string) (int, error)
+	SelectFunc func(prompt string, defaultValue string, options []string) (int, error)
 
 	// calls tracks calls to the methods.
 	calls struct {
@@ -85,34 +85,34 @@ type PrompterMock struct {
 		}
 		// Confirm holds details about calls to the Confirm method.
 		Confirm []struct {
-			// S is the s argument value.
-			S string
-			// B is the b argument value.
-			B bool
+			// Prompt is the prompt argument value.
+			Prompt string
+			// DefaultValue is the defaultValue argument value.
+			DefaultValue bool
 		}
 		// ConfirmDeletion holds details about calls to the ConfirmDeletion method.
 		ConfirmDeletion []struct {
-			// S is the s argument value.
-			S string
+			// RequiredValue is the requiredValue argument value.
+			RequiredValue string
 		}
 		// Input holds details about calls to the Input method.
 		Input []struct {
-			// S1 is the s1 argument value.
-			S1 string
-			// S2 is the s2 argument value.
-			S2 string
+			// Prompt is the prompt argument value.
+			Prompt string
+			// DefaultValue is the defaultValue argument value.
+			DefaultValue string
 		}
 		// InputHostname holds details about calls to the InputHostname method.
 		InputHostname []struct {
 		}
 		// MarkdownEditor holds details about calls to the MarkdownEditor method.
 		MarkdownEditor []struct {
-			// S1 is the s1 argument value.
-			S1 string
-			// S2 is the s2 argument value.
-			S2 string
-			// B is the b argument value.
-			B bool
+			// Prompt is the prompt argument value.
+			Prompt string
+			// DefaultValue is the defaultValue argument value.
+			DefaultValue string
+			// BlankAllowed is the blankAllowed argument value.
+			BlankAllowed bool
 		}
 		// MultiSelect holds details about calls to the MultiSelect method.
 		MultiSelect []struct {
@@ -125,17 +125,17 @@ type PrompterMock struct {
 		}
 		// Password holds details about calls to the Password method.
 		Password []struct {
-			// S is the s argument value.
-			S string
+			// Prompt is the prompt argument value.
+			Prompt string
 		}
 		// Select holds details about calls to the Select method.
 		Select []struct {
-			// S1 is the s1 argument value.
-			S1 string
-			// S2 is the s2 argument value.
-			S2 string
-			// Strings is the strings argument value.
-			Strings []string
+			// Prompt is the prompt argument value.
+			Prompt string
+			// DefaultValue is the defaultValue argument value.
+			DefaultValue string
+			// Options is the options argument value.
+			Options []string
 		}
 	}
 	lockAuthToken       sync.RWMutex
@@ -177,21 +177,21 @@ func (mock *PrompterMock) AuthTokenCalls() []struct {
 }
 
 // Confirm calls ConfirmFunc.
-func (mock *PrompterMock) Confirm(s string, b bool) (bool, error) {
+func (mock *PrompterMock) Confirm(prompt string, defaultValue bool) (bool, error) {
 	if mock.ConfirmFunc == nil {
 		panic("PrompterMock.ConfirmFunc: method is nil but Prompter.Confirm was just called")
 	}
 	callInfo := struct {
-		S string
-		B bool
+		Prompt       string
+		DefaultValue bool
 	}{
-		S: s,
-		B: b,
+		Prompt:       prompt,
+		DefaultValue: defaultValue,
 	}
 	mock.lockConfirm.Lock()
 	mock.calls.Confirm = append(mock.calls.Confirm, callInfo)
 	mock.lockConfirm.Unlock()
-	return mock.ConfirmFunc(s, b)
+	return mock.ConfirmFunc(prompt, defaultValue)
 }
 
 // ConfirmCalls gets all the calls that were made to Confirm.
@@ -199,12 +199,12 @@ func (mock *PrompterMock) Confirm(s string, b bool) (bool, error) {
 //
 //	len(mockedPrompter.ConfirmCalls())
 func (mock *PrompterMock) ConfirmCalls() []struct {
-	S string
-	B bool
+	Prompt       string
+	DefaultValue bool
 } {
 	var calls []struct {
-		S string
-		B bool
+		Prompt       string
+		DefaultValue bool
 	}
 	mock.lockConfirm.RLock()
 	calls = mock.calls.Confirm
@@ -213,19 +213,19 @@ func (mock *PrompterMock) ConfirmCalls() []struct {
 }
 
 // ConfirmDeletion calls ConfirmDeletionFunc.
-func (mock *PrompterMock) ConfirmDeletion(s string) error {
+func (mock *PrompterMock) ConfirmDeletion(requiredValue string) error {
 	if mock.ConfirmDeletionFunc == nil {
 		panic("PrompterMock.ConfirmDeletionFunc: method is nil but Prompter.ConfirmDeletion was just called")
 	}
 	callInfo := struct {
-		S string
+		RequiredValue string
 	}{
-		S: s,
+		RequiredValue: requiredValue,
 	}
 	mock.lockConfirmDeletion.Lock()
 	mock.calls.ConfirmDeletion = append(mock.calls.ConfirmDeletion, callInfo)
 	mock.lockConfirmDeletion.Unlock()
-	return mock.ConfirmDeletionFunc(s)
+	return mock.ConfirmDeletionFunc(requiredValue)
 }
 
 // ConfirmDeletionCalls gets all the calls that were made to ConfirmDeletion.
@@ -233,10 +233,10 @@ func (mock *PrompterMock) ConfirmDeletion(s string) error {
 //
 //	len(mockedPrompter.ConfirmDeletionCalls())
 func (mock *PrompterMock) ConfirmDeletionCalls() []struct {
-	S string
+	RequiredValue string
 } {
 	var calls []struct {
-		S string
+		RequiredValue string
 	}
 	mock.lockConfirmDeletion.RLock()
 	calls = mock.calls.ConfirmDeletion
@@ -245,21 +245,21 @@ func (mock *PrompterMock) ConfirmDeletionCalls() []struct {
 }
 
 // Input calls InputFunc.
-func (mock *PrompterMock) Input(s1 string, s2 string) (string, error) {
+func (mock *PrompterMock) Input(prompt string, defaultValue string) (string, error) {
 	if mock.InputFunc == nil {
 		panic("PrompterMock.InputFunc: method is nil but Prompter.Input was just called")
 	}
 	callInfo := struct {
-		S1 string
-		S2 string
+		Prompt       string
+		DefaultValue string
 	}{
-		S1: s1,
-		S2: s2,
+		Prompt:       prompt,
+		DefaultValue: defaultValue,
 	}
 	mock.lockInput.Lock()
 	mock.calls.Input = append(mock.calls.Input, callInfo)
 	mock.lockInput.Unlock()
-	return mock.InputFunc(s1, s2)
+	return mock.InputFunc(prompt, defaultValue)
 }
 
 // InputCalls gets all the calls that were made to Input.
@@ -267,12 +267,12 @@ func (mock *PrompterMock) Input(s1 string, s2 string) (string, error) {
 //
 //	len(mockedPrompter.InputCalls())
 func (mock *PrompterMock) InputCalls() []struct {
-	S1 string
-	S2 string
+	Prompt       string
+	DefaultValue string
 } {
 	var calls []struct {
-		S1 string
-		S2 string
+		Prompt       string
+		DefaultValue string
 	}
 	mock.lockInput.RLock()
 	calls = mock.calls.Input
@@ -308,23 +308,23 @@ func (mock *PrompterMock) InputHostnameCalls() []struct {
 }
 
 // MarkdownEditor calls MarkdownEditorFunc.
-func (mock *PrompterMock) MarkdownEditor(s1 string, s2 string, b bool) (string, error) {
+func (mock *PrompterMock) MarkdownEditor(prompt string, defaultValue string, blankAllowed bool) (string, error) {
 	if mock.MarkdownEditorFunc == nil {
 		panic("PrompterMock.MarkdownEditorFunc: method is nil but Prompter.MarkdownEditor was just called")
 	}
 	callInfo := struct {
-		S1 string
-		S2 string
-		B  bool
+		Prompt       string
+		DefaultValue string
+		BlankAllowed bool
 	}{
-		S1: s1,
-		S2: s2,
-		B:  b,
+		Prompt:       prompt,
+		DefaultValue: defaultValue,
+		BlankAllowed: blankAllowed,
 	}
 	mock.lockMarkdownEditor.Lock()
 	mock.calls.MarkdownEditor = append(mock.calls.MarkdownEditor, callInfo)
 	mock.lockMarkdownEditor.Unlock()
-	return mock.MarkdownEditorFunc(s1, s2, b)
+	return mock.MarkdownEditorFunc(prompt, defaultValue, blankAllowed)
 }
 
 // MarkdownEditorCalls gets all the calls that were made to MarkdownEditor.
@@ -332,14 +332,14 @@ func (mock *PrompterMock) MarkdownEditor(s1 string, s2 string, b bool) (string,
 //
 //	len(mockedPrompter.MarkdownEditorCalls())
 func (mock *PrompterMock) MarkdownEditorCalls() []struct {
-	S1 string
-	S2 string
-	B  bool
+	Prompt       string
+	DefaultValue string
+	BlankAllowed bool
 } {
 	var calls []struct {
-		S1 string
-		S2 string
-		B  bool
+		Prompt       string
+		DefaultValue string
+		BlankAllowed bool
 	}
 	mock.lockMarkdownEditor.RLock()
 	calls = mock.calls.MarkdownEditor
@@ -388,19 +388,19 @@ func (mock *PrompterMock) MultiSelectCalls() []struct {
 }
 
 // Password calls PasswordFunc.
-func (mock *PrompterMock) Password(s string) (string, error) {
+func (mock *PrompterMock) Password(prompt string) (string, error) {
 	if mock.PasswordFunc == nil {
 		panic("PrompterMock.PasswordFunc: method is nil but Prompter.Password was just called")
 	}
 	callInfo := struct {
-		S string
+		Prompt string
 	}{
-		S: s,
+		Prompt: prompt,
 	}
 	mock.lockPassword.Lock()
 	mock.calls.Password = append(mock.calls.Password, callInfo)
 	mock.lockPassword.Unlock()
-	return mock.PasswordFunc(s)
+	return mock.PasswordFunc(prompt)
 }
 
 // PasswordCalls gets all the calls that were made to Password.
@@ -408,10 +408,10 @@ func (mock *PrompterMock) Password(s string) (string, error) {
 //
 //	len(mockedPrompter.PasswordCalls())
 func (mock *PrompterMock) PasswordCalls() []struct {
-	S string
+	Prompt string
 } {
 	var calls []struct {
-		S string
+		Prompt string
 	}
 	mock.lockPassword.RLock()
 	calls = mock.calls.Password
@@ -420,23 +420,23 @@ func (mock *PrompterMock) PasswordCalls() []struct {
 }
 
 // Select calls SelectFunc.
-func (mock *PrompterMock) Select(s1 string, s2 string, strings []string) (int, error) {
+func (mock *PrompterMock) Select(prompt string, defaultValue string, options []string) (int, error) {
 	if mock.SelectFunc == nil {
 		panic("PrompterMock.SelectFunc: method is nil but Prompter.Select was just called")
 	}
 	callInfo := struct {
-		S1      string
-		S2      string
-		Strings []string
+		Prompt       string
+		DefaultValue string
+		Options      []string
 	}{
-		S1:      s1,
-		S2:      s2,
-		Strings: strings,
+		Prompt:       prompt,
+		DefaultValue: defaultValue,
+		Options:      options,
 	}
 	mock.lockSelect.Lock()
 	mock.calls.Select = append(mock.calls.Select, callInfo)
 	mock.lockSelect.Unlock()
-	return mock.SelectFunc(s1, s2, strings)
+	return mock.SelectFunc(prompt, defaultValue, options)
 }
 
 // SelectCalls gets all the calls that were made to Select.
@@ -444,14 +444,14 @@ func (mock *PrompterMock) Select(s1 string, s2 string, strings []string) (int, e
 //
 //	len(mockedPrompter.SelectCalls())
 func (mock *PrompterMock) SelectCalls() []struct {
-	S1      string
-	S2      string
-	Strings []string
+	Prompt       string
+	DefaultValue string
+	Options      []string
 } {
 	var calls []struct {
-		S1      string
-		S2      string
-		Strings []string
+		Prompt       string
+		DefaultValue string
+		Options      []string
 	}
 	mock.lockSelect.RLock()
 	calls = mock.calls.Select
diff --git a/pkg/cmd/root/help_topic.go b/pkg/cmd/root/help_topic.go
index 4b692777c..0c9534306 100644
--- a/pkg/cmd/root/help_topic.go
+++ b/pkg/cmd/root/help_topic.go
@@ -84,6 +84,8 @@ var HelpTopics = []helpTopic{
 			%[1]sGH_COLOR_LABELS%[1]s: set to any value to display labels using their RGB hex color codes in terminals that
 			support truecolor.
 
+			%[1]sGH_ACCESSIBLE_COLORS%[1]s (preview): set to a truthy value to use customizable, 4-bit accessible colors.
+
 			%[1]sGH_FORCE_TTY%[1]s: set to any value to force terminal-style output even when the output is
 			redirected. When the value is a number, it is interpreted as the number of columns
 			available in the viewport. When the value is a percentage, it will be applied against


Test patch:
diff --git a/pkg/cmd/config/list/list_test.go b/pkg/cmd/config/list/list_test.go
index 2184d0f16..2a1dd72ee 100644
--- a/pkg/cmd/config/list/list_test.go
+++ b/pkg/cmd/config/list/list_test.go
@@ -101,6 +101,7 @@ func Test_listRun(t *testing.T) {
 				http_unix_socket=
 				browser=brave
 				color_labels=disabled
+				accessible_colors=disabled
 			`),
 		},
 	}