Skip to content

Commit 07c7d91

Browse files
committed
fixup: fix incorrect parent PID detection bug
When Async ZLE helper code starts a coprocess it starts it in a subshell. This was at crossroads with assumption that the parent of the GoPrompt process is the user Shell. To remedy that add `--pid-parent-skip` option which is set to 1 to skip the extra subshell and render correct parent process name. NOTE: knowing the parent process is pretty handy to know if your session is nested.
1 parent 10fb8c4 commit 07c7d91

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

cmd/goprompt/cmdQuery.go

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"os"
78
"os/signal"
@@ -33,6 +34,14 @@ var (
3334
"timeout", 0,
3435
"timeout after which to give up",
3536
)
37+
flgQPidParentSkip = cmdQuery.PersistentFlags().Int(
38+
"pid-parent-skip", 0,
39+
"skip this many parent PIDs when determining true parent process (when run from ZSH ZLE descriptor we end up with extra PID nesting)",
40+
)
41+
flgQPidChain = cmdQuery.PersistentFlags().Bool(
42+
"pid-chain", false,
43+
"add extra pid parent chain information",
44+
)
3645
)
3746

3847
func init() {
@@ -51,13 +60,15 @@ const (
5160
_partWorkDir = "wd"
5261
_partWorkDirShort = "wd_trim"
5362

54-
_partPid = "pid"
55-
_partPidShell = "pid_shell"
56-
_partPidShellExec = "pid_shell_exec"
57-
_partPidParent = "pid_parent"
58-
_partPidParentExec = "pid_parent_exec"
59-
_partPidRemote = "pid_remote"
60-
_partPidRemoteExec = "pid_remote_exec"
63+
_partPid = "pid"
64+
_partPidShell = "pid_shell"
65+
_partPidShellExec = "pid_shell_exec"
66+
_partPidParent = "pid_parent"
67+
_partPidParentExec = "pid_parent_exec"
68+
_partPidRemote = "pid_remote"
69+
_partPidRemoteExec = "pid_remote_exec"
70+
_partPidChain = "pid_chain"
71+
_partPidChainLength = "pid_chain_length"
6172

6273
_partSessionUsername = "session_username"
6374
_partSessionHostname = "session_hostname"
@@ -75,8 +86,8 @@ const (
7586
_partVcsStgTop = "vcs_git_stg_top"
7687
_partVcsStgDirty = "vcs_git_stg_dirty"
7788

78-
_partVcsGitRebaseOp = "vcs_git_rebase_op"
79-
_partVcsGitRebaseLeft = "vcs_git_rebase_op_left"
89+
_partVcsGitRebaseOp = "vcs_git_rebase_op"
90+
_partVcsGitRebaseLeft = "vcs_git_rebase_op_left"
8091

8192
_partVcsGitIdxTotal = "vcs_git_idx_total"
8293
_partVcsGitIdxIncluded = "vcs_git_idx_incl"
@@ -190,37 +201,53 @@ func cmdQueryRun(_ *cobra.Command, _ []string) error {
190201
})
191202

192203
tasks.Go(func(_ context.Context) error {
204+
type list []interface{}
205+
type dict map[string]interface{}
206+
193207
psChain, err := moduleFindProcessChain()
194208
if err != nil {
195209
return nil
196210
}
197211

198-
if len(psChain) > 3 {
199-
pidShell := psChain[1]
200-
pidShellParent := psChain[2]
212+
printPart(_partPidChainLength, len(psChain))
201213

202-
pidShellExecName, _, _ := strings.Cut(pidShell.Executable(), " ")
203-
printPart(_partPidShell, pidShell.Pid())
204-
printPart(_partPidShellExec, pidShellExecName)
214+
var pidRemote ps.Process
215+
var pidChain list
216+
for psIdx, ps := range psChain {
217+
pidChain = append(pidChain, dict{
218+
"name": ps.Executable(),
219+
"pid": ps.Pid(),
220+
})
221+
222+
// Find if we are in a remote session.
223+
if strings.Contains(ps.Executable(), "ssh") && pidRemote == nil {
224+
pidRemote = ps
225+
}
205226

206-
pidShellParentExecName, _, _ := strings.Cut(pidShellParent.Executable(), " ")
207-
printPart(_partPidParent, pidShellParent.Pid())
208-
printPart(_partPidParentExec, pidShellParentExecName)
209-
}
227+
psIdxAdj := psIdx - *flgQPidParentSkip
210228

211-
var pidRemote ps.Process
212-
for _, psInfo := range psChain {
213-
if strings.Contains(psInfo.Executable(), "ssh") {
214-
pidRemote = psInfo
215-
break
229+
if psIdxAdj == 1 {
230+
pidShellExecName, _, _ := strings.Cut(ps.Executable(), " ")
231+
printPart(_partPidShell, ps.Pid())
232+
printPart(_partPidShellExec, pidShellExecName)
233+
} else if psIdxAdj == 2 {
234+
pidShellParentExecName, _, _ := strings.Cut(ps.Executable(), " ")
235+
printPart(_partPidParent, ps.Pid())
236+
printPart(_partPidParentExec, pidShellParentExecName)
216237
}
217238
}
239+
218240
if pidRemote != nil {
219241
pidShellRemoteExecName, _, _ := strings.Cut(pidRemote.Executable(), " ")
220242
printPart(_partPidRemote, pidRemote.Pid())
221243
printPart(_partPidRemoteExec, pidShellRemoteExecName)
222244
}
223245

246+
if *flgQPidChain {
247+
pidChainJson, _ := json.Marshal(pidChain)
248+
printPart(_partPidChain, string(pidChainJson))
249+
}
250+
224251
return nil
225252
})
226253

@@ -253,7 +280,6 @@ func cmdQueryRun(_ *cobra.Command, _ []string) error {
253280
return nil
254281
})
255282

256-
257283
subTasks.Go(func(ctx context.Context) error {
258284
if saplStatus, err := stringExec("sl", "status"); err == nil {
259285
if len(saplStatus) == 0 {
@@ -284,8 +310,6 @@ func cmdQueryRun(_ *cobra.Command, _ []string) error {
284310

285311
subTasks.Go(func(ctx context.Context) error {
286312

287-
288-
289313
headRef := ""
290314
if cherryHeadB, _ := os.ReadFile(filepath.Join(gitDir, "CHERRY_PICK_HEAD")); len(cherryHeadB) > 0 {
291315
headRef = trim(string(cherryHeadB))

plugin/zsh/prompt_asynczle_setup.zsh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ __async_prompt_query() {
3939
${G_GOPROMPT} query \
4040
--cmd-status "$G_LAST_STATUS" \
4141
--preexec-ts "$G_PREEXEC_TS" \
42+
--pid-parent-skip 1 \
4243
--timeout "$ZSH_ASYNC_PROMPT_TIMEOUT"
4344
}
4445

0 commit comments

Comments
 (0)