authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-20 10:59:54-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-20 10:59:54-07:00
log71608142c27136a5ba0551fe9ed52ceeaad22ee4
tree2bd67ddf1755c16a7f786576b692d1c120025a63
parentbf1a6501c7ada5822f0c68e8e5a0aa6bdbb9c1b7
signature Signed by PGP key B5690EEEBB952194

[codex] Split preferred editor precondition errors (#3324)

Co-authored-by: codex <codex@users.noreply.github.com>

1 files changed, 35 insertions(+), 10 deletions(-)

apps/web/src/editorPreferences.ts+35-10
......@@ -1,11 +1,11 @@
1import { EDITORS, EditorId, type EnvironmentId } from "@t3tools/contracts";
1import { EDITORS, EditorId, EnvironmentId } from "@t3tools/contracts";
22import {
33 mapAtomCommandResult,
44 type AtomCommandFailure,
55 type AtomCommandResult,
66} from "@t3tools/client-runtime/state/runtime";
77import * as Cause from "effect/Cause";
8import * as Data from "effect/Data";
8import * as Schema from "effect/Schema";
99import { AsyncResult } from "effect/unstable/reactivity";
1010import { getLocalStorageItem, setLocalStorageItem, useLocalStorage } from "./hooks/useLocalStorage";
1111import { useCallback, useMemo } from "react";
......@@ -14,11 +14,29 @@ import { useAtomCommand } from "./state/use-atom-command";
1414
1515const LAST_EDITOR_KEY = "t3code:last-editor";
1616
17export class PreferredEditorUnavailableError extends Data.TaggedError(
17export class PreferredEditorEnvironmentRequiredError extends Schema.TaggedErrorClass<PreferredEditorEnvironmentRequiredError>()(
18 "PreferredEditorEnvironmentRequiredError",
19 {
20 targetPath: Schema.String,
21 },
22) {
23 override get message(): string {
24 return `Cannot open ${this.targetPath} because no environment is selected.`;
25 }
26}
27
28export class PreferredEditorUnavailableError extends Schema.TaggedErrorClass<PreferredEditorUnavailableError>()(
1829 "PreferredEditorUnavailableError",
19)<{
20 readonly message: string;
21}> {}
30 {
31 environmentId: EnvironmentId,
32 targetPath: Schema.String,
33 availableEditorIds: Schema.Array(EditorId),
34 },
35) {
36 override get message(): string {
37 return `No available editor can open ${this.targetPath} in environment ${this.environmentId}.`;
38 }
39}
2240
2341export function usePreferredEditor(availableEditors: ReadonlyArray<EditorId>) {
2442 const [lastEditor, setLastEditor] = useLocalStorage(LAST_EDITOR_KEY, null, EditorId);
......@@ -55,13 +73,18 @@ export function useOpenInPreferredEditor(
5573 async (
5674 targetPath: string,
5775 ): Promise<
58 AtomCommandResult<EditorId, OpenInEditorError | PreferredEditorUnavailableError>
76 AtomCommandResult<
77 EditorId,
78 | OpenInEditorError
79 | PreferredEditorEnvironmentRequiredError
80 | PreferredEditorUnavailableError
81 >
5982 > => {
6083 if (environmentId === null) {
6184 return AsyncResult.failure(
6285 Cause.fail(
63 new PreferredEditorUnavailableError({
64 message: "No environment is selected.",
86 new PreferredEditorEnvironmentRequiredError({
87 targetPath,
6588 }),
6689 ),
6790 );
......@@ -71,7 +94,9 @@ export function useOpenInPreferredEditor(
7194 return AsyncResult.failure(
7295 Cause.fail(
7396 new PreferredEditorUnavailableError({
74 message: "No available editors found.",
97 environmentId,
98 targetPath,
99 availableEditorIds: availableEditors,
75100 }),
76101 ),
77102 );