v0.48.1 deaab59

python_proc_windows.go RawHistoryFolder

1//go:build windows
2
3package tools
4
5import (
6	"bytes"
7	"context"
8	"io"
9	"os/exec"
10	"strconv"
11	"sync"
12	"syscall"
13	"time"
14)
15
16// pythonProcessWaitDelay bounds process cleanup beyond the invocation or
17// probe deadline. Bounded return is required; absolute containment of every
18// detached descendant is not promised.
19const pythonProcessWaitDelay = 5 * time.Second
20
21// pythonTreeKillTimeout bounds the tree-termination subprocess. On
22// failure or timeout the caller falls back to a direct process kill.
23const pythonTreeKillTimeout = 2 * time.Second
24
25// maxPythonKillOutput bounds termination-command output.
26const maxPythonKillOutput = 4 * 1024
27
28// configurePythonProcess makes context cancellation terminate the Python
29// process tree on Windows and closes the output pipe exactly once. Unlike
30// Bash's unbounded taskkill path, tree termination is bounded with a
31// direct-kill fallback. When cancelErr is non-nil, the termination error
32// from the Cancel callback is recorded there (guarded by its mutex):
33// Wait folds that error into its own process error, so without this
34// capture the cleanup detail is unreachable and a partial kill cannot
35// report surviving descendants.
36func configurePythonProcess(cmd *exec.Cmd, output io.Closer, cancelErr *pythonCancelError) func() {
37	if cmd != nil {
38		cmd.SysProcAttr = &syscall.SysProcAttr{
39			CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
40		}
41		cmd.WaitDelay = pythonProcessWaitDelay
42	}
43	var closeOutput sync.Once
44	closePipe := func() {
45		closeOutput.Do(func() {
46			if output != nil {
47				_ = output.Close()
48			}
49		})
50	}
51	if cmd != nil {
52		cmd.Cancel = func() error {
53			closePipe()
54			err := killPythonProcessTree(cmd)
55			if cancelErr != nil {
56				cancelErr.set(err)
57			}
58			return err
59		}
60	}
61	return closePipe
62}
63
64// killPythonProcessTree terminates the process tree with a bounded
65// taskkill call, then falls back to a direct kill on failure or timeout.
66func killPythonProcessTree(cmd *exec.Cmd) error {
67	if cmd == nil || cmd.Process == nil {
68		return nil
69	}
70	if err := boundedTaskkill(cmd.Process.Pid); err != nil {
71		_ = cmd.Process.Kill()
72		return err
73	}
74	return nil
75}
76
77func boundedTaskkill(pid int) error {
78	if pid <= 0 {
79		return nil
80	}
81	ctx, cancel := context.WithTimeout(context.Background(), pythonTreeKillTimeout)
82	defer cancel()
83	killCmd := exec.CommandContext(ctx, "taskkill", "/PID", strconv.Itoa(pid), "/T", "/F")
84	var out bytes.Buffer
85	killCmd.Stdout = &limitedWriter{W: &out, N: maxPythonKillOutput}
86	killCmd.Stderr = &limitedWriter{W: &out, N: maxPythonKillOutput}
87	if err := killCmd.Run(); err != nil {
88		return err
89	}
90	return ctx.Err()
91}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close