Skip to content

Commit ea762ce

Browse files
authored
feat(shell): detecting VSCode shell startup to prevent hook issues (#560)
1 parent e5391a0 commit ea762ce

File tree

6 files changed

+61
-10
lines changed

6 files changed

+61
-10
lines changed

cmd/commands/activate.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
"github.com/urfave/cli/v3"
2929
"github.com/version-fox/vfox/internal/env"
30+
"github.com/version-fox/vfox/internal/logger"
3031
"github.com/version-fox/vfox/internal/shell"
3132
)
3233

@@ -58,15 +59,22 @@ func activateCmd(ctx context.Context, cmd *cli.Command) error {
5859

5960
exportEnvs := sdkEnvs.ToExportEnvs()
6061

61-
exportEnvs[env.HookFlag] = &name
62-
exportEnvs[internal.HookCurTmpPath] = &manager.PathMeta.CurTmpPath
62+
// Current shell is not for user use, it will be killed after the activation.
63+
// If we setup hook in this shell, it will cause all terminal launched by IDE could not be hooked properly.
64+
if !env.IsIDEEnvironmentResolution() {
65+
exportEnvs[env.HookFlag] = &name
66+
exportEnvs[internal.HookCurTmpPath] = &manager.PathMeta.CurTmpPath
67+
}
68+
69+
logger.Debugf("export envs: %+v", exportEnvs)
6370

6471
path := manager.PathMeta.ExecutablePath
6572
path = strings.Replace(path, "\\", "/", -1)
6673
s := shell.NewShell(name)
6774
if s == nil {
6875
return fmt.Errorf("unknown target shell %s", name)
6976
}
77+
7078
exportStr := s.Export(exportEnvs)
7179
str, err := s.Activate(
7280
shell.ActivateConfig{

internal/env/env.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,11 @@ type Envs struct {
3737
BinPaths *Paths
3838
Paths *Paths
3939
}
40+
41+
func (e *Envs) MergePaths(envs *Envs) {
42+
if envs == nil {
43+
return
44+
}
45+
e.BinPaths.Merge(envs.BinPaths)
46+
e.Paths.Merge(envs.Paths)
47+
}

internal/env/flag.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,30 @@ func IsHookEnv() bool {
3535
return os.Getenv(HookFlag) != ""
3636
}
3737

38+
// IsIDEEnvironmentResolution detects if the current shell session was launched by an IDE
39+
// for the purpose of environment variable resolution. This is useful to avoid certain
40+
// shell initialization behaviors that might interfere with IDE environment detection.
41+
//
42+
// Supported IDEs:
43+
// - Visual Studio Code: Detects via VSCODE_RESOLVING_ENVIRONMENT environment variable
44+
// Reference: https://code.visualstudio.com/docs/configure/command-line#_how-do-i-detect-when-a-shell-was-launched-by-vs-code
45+
// - JetBrains IDEs (IntelliJ IDEA, PyCharm, etc.): Detects via INTELLIJ_ENVIRONMENT_READER environment variable
46+
// Reference: https://youtrack.jetbrains.com/articles/SUPPORT-A-1727/Shell-Environment-Loading
47+
//
48+
// Returns true if any of the supported IDE environment resolution indicators are present.
49+
func IsIDEEnvironmentResolution() bool {
50+
return os.Getenv("VSCODE_RESOLVING_ENVIRONMENT") != "" ||
51+
os.Getenv("INTELLIJ_ENVIRONMENT_READER") != ""
52+
}
53+
3854
func GetPid() int {
39-
if pid := os.Getenv(PidFlag); pid != "" {
40-
p, _ := strconv.Atoi(pid) // Convert pid from string to int
41-
return p
55+
if IsHookEnv() {
56+
if pid := os.Getenv(PidFlag); pid != "" {
57+
p, _ := strconv.Atoi(pid) // Convert pid from string to int
58+
return p
59+
}
4260
}
61+
4362
return os.Getppid()
4463
}
4564

internal/env/path.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ package env
1818

1919
import (
2020
"fmt"
21-
"github.com/version-fox/vfox/internal/logger"
22-
"github.com/version-fox/vfox/internal/util"
2321
"os"
2422
"path/filepath"
2523
"strings"
24+
25+
"github.com/version-fox/vfox/internal/logger"
26+
"github.com/version-fox/vfox/internal/util"
2627
)
2728

2829
type PathFrom int
@@ -38,6 +39,9 @@ type Paths struct {
3839
}
3940

4041
func (p *Paths) Merge(other *Paths) *Paths {
42+
if other == nil {
43+
return p
44+
}
4145
for _, path := range other.Slice() {
4246
p.Add(path)
4347
}

internal/sdk.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,15 @@ func (b *Sdk) Install(version base.Version) error {
165165
pterm.Printf("Install %s success! \n", pterm.LightGreen(label))
166166
useCommand := fmt.Sprintf("vfox use %s", label)
167167
pterm.Printf("Please use `%s` to use it.\n", pterm.LightBlue(useCommand))
168-
168+
169169
// Copy command to clipboard in TTY mode
170170
if util.IsTTY() {
171171
if err := util.CopyToClipboard(useCommand); err == nil {
172172
pterm.Printf("%s\n", pterm.LightYellow("Copied to clipboard, you can paste it now."))
173173
}
174174
// Silently ignore clipboard errors (not supported, utility not found, etc.)
175175
}
176-
176+
177177
return nil
178178
}
179179

@@ -347,6 +347,18 @@ func (b *Sdk) EnvKeys(version base.Version, location base.Location) (*env.Envs,
347347
if err != nil {
348348
return nil, fmt.Errorf("plugin [EnvKeys] error: err:%w", err)
349349
}
350+
351+
if env.IsIDEEnvironmentResolution() {
352+
// current shell will be killed after the activation,
353+
// so we need to run into something like `shims` mode.
354+
rawKeys, err := b.Plugin.EnvKeys(linkPackage.from)
355+
if err != nil {
356+
return nil, fmt.Errorf("plugin [EnvKeys] error: err:%w", err)
357+
}
358+
359+
keys.MergePaths(rawKeys)
360+
}
361+
350362
return keys, nil
351363
}
352364

internal/shell/zsh.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type zsh struct{}
2525
var Zsh = zsh{}
2626

2727
const zshHook = `
28-
if [[ -z "$__VFOX_PID" ]]; then
28+
if [[ -z "$__VFOX_PID" || -z "$__VFOX_SHELL" ]]; then
2929
{{.EnvContent}}
3030
3131
export __VFOX_PID=$$;

0 commit comments

Comments
 (0)