@young1lin/dsh-ui-gitworkbench 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/CHANGELOG_EN.md +13 -0
- package/README.md +51 -0
- package/lib/client.js +346 -308
- package/lib/index.js +163 -85
- package/lib/repo-root.js +60 -0
- package/package.json +5 -5
- package/src/client/DiffViews.tsx +41 -12
- package/src/client/cr-mark.ts +39 -0
- package/src/client/locales.ts +4 -4
- package/src/client/styles/changes.css +8 -0
- package/src/index.ts +164 -84
- package/src/repo-root.ts +66 -0
package/src/repo-root.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the drawer runs git: at the repository ROOT, not at the directory the
|
|
3
|
+
* session happened to open.
|
|
4
|
+
*
|
|
5
|
+
* Every path the drawer carries — the tree's entries, the diff's pathspecs,
|
|
6
|
+
* the editor's save target — is REPOSITORY-RELATIVE, because that is what
|
|
7
|
+
* `git status --porcelain` and `git diff --numstat` print wherever they run.
|
|
8
|
+
* Pathspecs and `:path` revisions are the opposite: git resolves them against
|
|
9
|
+
* the process cwd. The two coincide only when the session opened the root
|
|
10
|
+
* itself. A session opened at a subdirectory (a monorepo's `server/`, say)
|
|
11
|
+
* gets a drawer that LISTS the right files and then quietly fails to do
|
|
12
|
+
* anything with them: `git diff HEAD -- server/main.go` run from `server/`
|
|
13
|
+
* looks for `server/server/main.go`, matches nothing, and exits 0 with empty
|
|
14
|
+
* output — a changed file that opens to a blank pane, a stage tick that dies
|
|
15
|
+
* with "pathspec did not match", a blame that cannot find the path in HEAD.
|
|
16
|
+
*
|
|
17
|
+
* Resolving the root once and running everything there makes every
|
|
18
|
+
* repository-relative spelling correct by construction, whatever directory the
|
|
19
|
+
* session opened. The resolve is a real git spawn per RPC entry — folded into
|
|
20
|
+
* the parallel batch where a poll pays for it — and deliberately NOT cached:
|
|
21
|
+
* re-resolving per call is what lets `git init` run inside a subdirectory
|
|
22
|
+
* mid-session and be picked up by the next poll, and a cache would trade that
|
|
23
|
+
* for a spawn that already runs concurrently with the reads it precedes.
|
|
24
|
+
*
|
|
25
|
+
* Pure and git-injected (the `write-checked` pattern) so vitest can pin both
|
|
26
|
+
* halves: the resolution itself, and the git behaviors the whole arrangement
|
|
27
|
+
* rests on.
|
|
28
|
+
*
|
|
29
|
+
* @module @young1lin/dsh-ui-gitworkbench/repo-root
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import type { GitRun } from './apply-blocks.js'
|
|
33
|
+
|
|
34
|
+
/** Run git in `cwd`. Must not throw — report through `exitCode`/`stderr`. */
|
|
35
|
+
export type RootGit = (cwd: string, argv: readonly string[]) => Promise<GitRun>
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The repository root of a directory, or null when git knows none.
|
|
39
|
+
*
|
|
40
|
+
* `--show-toplevel` is the discovery git itself uses, so what it returns is by
|
|
41
|
+
* definition where the porcelain paths of commands run in that directory are
|
|
42
|
+
* rooted — including a linked worktree's own root when the directory sits in
|
|
43
|
+
* one. Output is normalized to forward slashes so `join()` behaves the same on
|
|
44
|
+
* every platform (git for Windows already prints them that way).
|
|
45
|
+
* @param git - how to run git.
|
|
46
|
+
* @param cwd - any directory inside the repository.
|
|
47
|
+
*/
|
|
48
|
+
export async function resolveRepoRoot(git: RootGit, cwd: string): Promise<string | null> {
|
|
49
|
+
const out = await git(cwd, ['rev-parse', '--show-toplevel'])
|
|
50
|
+
if (out.exitCode !== 0) return null
|
|
51
|
+
return out.stdout.trim().replace(/\\/g, '/') || null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The directory to run git in for a session's workspace: its repository root,
|
|
56
|
+
* or the directory itself when it is not inside a repository.
|
|
57
|
+
*
|
|
58
|
+
* The fallback keeps the failure honest: outside a repository the caller's own
|
|
59
|
+
* git run fails exactly as it did before this module existed, and that error —
|
|
60
|
+
* not a resolution error — is what the reader should see.
|
|
61
|
+
* @param git - how to run git.
|
|
62
|
+
* @param cwd - the directory the session opened.
|
|
63
|
+
*/
|
|
64
|
+
export async function rootedDir(git: RootGit, cwd: string): Promise<string> {
|
|
65
|
+
return (await resolveRepoRoot(git, cwd)) ?? cwd
|
|
66
|
+
}
|