4.3 KB126 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {CommitInfo, RepoInfo, RepoRelativePath} from './types';
9
10import {atom, useAtomValue} from 'jotai';
11import {atomResetOnDepChange, localStorageBackedAtom} from './jotaiUtils';
12import platform from './platform';
13
14export const repositoryData = atom<{info?: RepoInfo; cwd?: string}>({});
15
16/** "cwd" is not always the repo root. It can be a path inside the repo. */
17export const serverCwd = atom<string>(get => {
18 const data = get(repositoryData);
19 if (data.info?.type === 'cwdNotARepository') {
20 return data.info.cwd;
21 }
22 return data?.cwd ?? platform.initialUrlParams?.get('cwd') ?? '';
23});
24
25export const repoRootAtom = atom(get => {
26 const data = get(repositoryData);
27 return data.info?.type === 'success' ? data.info.repoRoot : '';
28});
29
30export const repoRelativeCwd = atom<RepoRelativePath>(get => {
31 const cwd = get(serverCwd);
32 const root = get(repoRootAtom);
33 return cwd.startsWith(root) ? cwd.slice(root.length + 1) + '/' : cwd;
34});
35
36/**
37 * Returns true if the commit is irrelevant to the current cwd,
38 * due to it modifying only files in folders that are not under the cwd.
39 * If the max prefix is "inside" the cwd, it is NOT irrelevant.
40 * > if the max prefix is `addons/isl` and the cwd is `addons`, it is NOT irrelevant.
41 * If the max prefix is "above" the cwd, it is NOT irrelevant.
42 * > if the max prefix is `addons` and the cwd is `addons/isl`, it is NOT irrelevant.
43 * Only if the max prefix contains portions that do not match the cwd is it irrelevant.
44 * > if the max prefix is `addons/isl` and the cwd is `www`, it IS irrelevant.
45 * Thus, if the cwd is the repo root, it is never irrelevant.
46 *
47 * If a commit has only irrelevant files, but then a relevant file is added, the commit
48 * is guaranteed to become relevant, since the common portion of the paths will
49 * be a prefix of the relevant file.
50 */
51export const useIsIrrelevantToCwd = (commit: CommitInfo) => {
52 const isEnabled = useAtomValue(irrelevantCwdDeemphasisEnabled);
53 const cwd = useAtomValue(repoRelativeCwd);
54 if (!isEnabled) {
55 return false;
56 }
57 return isIrrelevantToCwd(commit, cwd);
58};
59
60export function isIrrelevantToCwd(commit: CommitInfo, repoRelativeCwd: RepoRelativePath): boolean {
61 return (
62 repoRelativeCwd !== '/' &&
63 !commit.maxCommonPathPrefix.startsWith(repoRelativeCwd) &&
64 !repoRelativeCwd.startsWith(commit.maxCommonPathPrefix)
65 );
66}
67export const __TEST__ = {isIrrelevantToCwd};
68
69export const irrelevantCwdDeemphasisEnabled = localStorageBackedAtom<boolean>(
70 'isl.deemphasize-cwd-irrelevant-commits',
71 true,
72);
73
74export const hideIrrelevantCwdStacks = localStorageBackedAtom<boolean>(
75 'isl.hide-cwd-irrelevant-stacks',
76 false,
77);
78
79/**
80 * Derived atom that combines the irrelevant CWD display settings into a single value.
81 * - 'show': Show irrelevant commits normally (deemphasis disabled)
82 * - 'deemphasize': Show irrelevant commits but with reduced visual prominence
83 * - 'hide': Don't show irrelevant commits at all
84 */
85export const irrelevantCwdDisplayModeAtom = atom(
86 get => {
87 const deemphasizeEnabled = get(irrelevantCwdDeemphasisEnabled);
88 const hideEnabled = get(hideIrrelevantCwdStacks);
89
90 if (hideEnabled) {
91 return 'hide';
92 }
93 if (deemphasizeEnabled) {
94 return 'deemphasize';
95 }
96 return 'show';
97 },
98 (_get, set, newValue: 'show' | 'deemphasize' | 'hide') => {
99 switch (newValue) {
100 case 'show':
101 set(irrelevantCwdDeemphasisEnabled, false);
102 set(hideIrrelevantCwdStacks, false);
103 break;
104 case 'deemphasize':
105 set(irrelevantCwdDeemphasisEnabled, true);
106 set(hideIrrelevantCwdStacks, false);
107 break;
108 case 'hide':
109 set(irrelevantCwdDeemphasisEnabled, true);
110 set(hideIrrelevantCwdStacks, true);
111 break;
112 }
113 },
114);
115
116/**
117 * A string of repo root and the "cwd". Note a same "cwd" does not infer the same repo,
118 * when there are nested (ex. submodule) repos.
119 */
120export const repoRootAndCwd = atom<string>(get => `${get(serverCwd)}\n${get(repoRootAtom)}`);
121
122/** A specific version of `atomResetOnDepChange`. */
123export function atomResetOnCwdChange<T>(defaultValue: T) {
124 return atomResetOnDepChange(defaultValue, repoRootAndCwd);
125}
126