feat: add shell login option (#75)

Closes #72
This commit is contained in:
Paolo Ricciuti
2026-07-30 22:45:23 +07:00
committed by GitHub
parent 37182f7212
commit 2573ad73b4
10 changed files with 103 additions and 12 deletions
+3
View File
@@ -43,6 +43,9 @@ version = 1
# override shell: "bash", "zsh", "fish", keep empty for auto detection
shell = ""
# run the selected shell as a login shell
shell-login = false
# startup mode: "last", "spec", "history"
# "last" = remember last mode used
mode = "last"
+18 -3
View File
@@ -3,8 +3,10 @@ package root
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"github.com/versenilvis/iris/internal/config"
)
func TestConfigCommands(t *testing.T) {
@@ -14,14 +16,27 @@ func TestConfigCommands(t *testing.T) {
}
defer os.RemoveAll(tmpDir)
// UserConfigDir follows HOME on macOS and XDG_CONFIG_HOME on Unix.
// Override both so the command cannot read or write the user's real config.
t.Setenv("HOME", tmpDir)
t.Setenv("XDG_CONFIG_HOME", tmpDir)
ConfigInitCmd.Run(ConfigInitCmd, []string{})
configPath := filepath.Join(tmpDir, "iris", "config.toml")
if _, err := os.Stat(configPath); err != nil {
configPath, err := config.ConfigPath()
if err != nil {
t.Fatalf("failed to get config path: %v", err)
}
if _, statErr := os.Stat(configPath); statErr != nil {
t.Errorf("expected config file to be created at %s, but it was not", configPath)
}
content, err := os.ReadFile(configPath)
if err != nil {
t.Fatalf("failed to read config file: %v", err)
}
if !strings.Contains(string(content), "shell-login = false") {
t.Error("expected initialized config to include shell-login = false")
}
buf := new(bytes.Buffer)
ConfigShowCmd.SetOut(buf)
+4 -1
View File
@@ -148,7 +148,7 @@ var setupCmd = &cobra.Command{
var shellName string
if len(args) > 0 {
shellName = args[0]
shellName = filepath.Base(args[0])
} else {
shellPath := os.Getenv("SHELL")
shellName = filepath.Base(shellPath)
@@ -208,6 +208,9 @@ version = 1
# override shell: "bash", "zsh", "fish", keep empty for auto detection
shell = ""
# run the selected shell as a login shell
shell-login = false
# startup mode: "last", "spec", "history"
# "last" = remember last mode used
mode = "last"
+8 -3
View File
@@ -50,24 +50,29 @@ It works exactly like coding editor suggestion menu drop down.`,
runWrapper()
},
}
shellFlag string
debugMode bool
shellFlag string
shellLoginFlag bool
debugMode bool
)
func init() {
rootCmd.PersistentFlags().StringVarP(&shellFlag, "shell", "s", "", "shell to use (bash, zsh, fish)")
rootCmd.PersistentFlags().BoolVar(&shellLoginFlag, "shell-login", false, "run the selected shell as a login shell")
rootCmd.PersistentFlags().BoolVarP(&debugMode, "debug", "d", false, "enable debug logging to iris.log")
rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
if shellFlag != "" {
config.Get().Core.Shell = shellFlag
}
if cmd.Flags().Changed("shell-login") {
config.Get().Core.ShellLogin = shellLoginFlag
}
logDir, err := config.CachePath()
if err == nil {
logger.Init(filepath.Join(logDir, "iris.log"), debugMode || config.Get().Core.Debug)
logger.Infof("IRIS session started: os=%s, arch=%s, go=%s, pid=%d", runtime.GOOS, runtime.GOARCH, runtime.Version(), os.Getpid())
cfg := config.Get()
logger.Debugf("IRIS loaded config: shell=%q, mode=%q, ghost-text=%v, max-suggestions=%d", cfg.Core.Shell, cfg.Core.Mode, cfg.UI.GhostText, cfg.UI.MaxSuggestions)
logger.Debugf("IRIS loaded config: shell=%q, shell-login=%v, mode=%q, ghost-text=%v, max-suggestions=%d", cfg.Core.Shell, cfg.Core.ShellLogin, cfg.Core.Mode, cfg.UI.GhostText, cfg.UI.MaxSuggestions)
}
}
}
+35
View File
@@ -0,0 +1,35 @@
package root
import (
"reflect"
"testing"
)
func TestShellArgs(t *testing.T) {
tests := []struct {
name string
login bool
want []string
}{
{name: "login", login: true, want: []string{"--login"}},
{name: "non-login", login: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := shellArgs(tt.login); !reflect.DeepEqual(got, tt.want) {
t.Fatalf("shellArgs(%v) = %v, want %v", tt.login, got, tt.want)
}
})
}
}
func TestShellLoginFlagIsRegistered(t *testing.T) {
flag := rootCmd.PersistentFlags().Lookup("shell-login")
if flag == nil {
t.Fatal("expected --shell-login flag to be registered")
}
if flag.DefValue != "false" {
t.Fatalf("expected --shell-login to default to false, got %q", flag.DefValue)
}
}
+8 -1
View File
@@ -82,6 +82,13 @@ func saveMode(mode string) {
_ = config.SaveState(state)
}
func shellArgs(login bool) []string {
if login {
return []string{"--login"}
}
return nil
}
var (
oldState *term.State
oldStateFd int
@@ -141,7 +148,7 @@ func runWrapper() {
adapter := shell.Current
ctx := context.Background()
c := exec.CommandContext(ctx, adapter.GetShellPath())
c := exec.CommandContext(ctx, adapter.GetShellPath(), shellArgs(config.Get().Core.ShellLogin)...)
c.ExtraFiles = make([]*os.File, 11)
// pass write end of pipe to shell as fd 13 (since index 10 maps to 13)
c.ExtraFiles[10] = w