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 @@...@@ -1,11 +1,11 @@
1import { EDITORS, EditorId, type EnvironmentId } from "@t3tools/contracts";1import { EDITORS, EditorId, EnvironmentId } from "@t3tools/contracts";
2import {2import {
3 mapAtomCommandResult,3 mapAtomCommandResult,
4 type AtomCommandFailure,4 type AtomCommandFailure,
5 type AtomCommandResult,5 type AtomCommandResult,
6} from "@t3tools/client-runtime/state/runtime";6} from "@t3tools/client-runtime/state/runtime";
7import * as Cause from "effect/Cause";7import * as Cause from "effect/Cause";
8import * as Data from "effect/Data";8import * as Schema from "effect/Schema";
9import { AsyncResult } from "effect/unstable/reactivity";9import { AsyncResult } from "effect/unstable/reactivity";
10import { getLocalStorageItem, setLocalStorageItem, useLocalStorage } from "./hooks/useLocalStorage";10import { getLocalStorageItem, setLocalStorageItem, useLocalStorage } from "./hooks/useLocalStorage";
11import { useCallback, useMemo } from "react";11import { useCallback, useMemo } from "react";
...@@ -14,11 +14,29 @@ import { useAtomCommand } from "./state/use-atom-command";...@@ -14,11 +14,29 @@ import { useAtomCommand } from "./state/use-atom-command";
1414
15const LAST_EDITOR_KEY = "t3code:last-editor";15const 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>()(
18 "PreferredEditorUnavailableError",29 "PreferredEditorUnavailableError",
19)<{30 {
20 readonly message: string;31 environmentId: EnvironmentId,
21}> {}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
23export function usePreferredEditor(availableEditors: ReadonlyArray<EditorId>) {41export function usePreferredEditor(availableEditors: ReadonlyArray<EditorId>) {
24 const [lastEditor, setLastEditor] = useLocalStorage(LAST_EDITOR_KEY, null, EditorId);42 const [lastEditor, setLastEditor] = useLocalStorage(LAST_EDITOR_KEY, null, EditorId);
...@@ -55,13 +73,18 @@ export function useOpenInPreferredEditor(...@@ -55,13 +73,18 @@ export function useOpenInPreferredEditor(
55 async (73 async (
56 targetPath: string,74 targetPath: string,
57 ): Promise<75 ): Promise<
58 AtomCommandResult<EditorId, OpenInEditorError | PreferredEditorUnavailableError>76 AtomCommandResult<
77 EditorId,
78 | OpenInEditorError
79 | PreferredEditorEnvironmentRequiredError
80 | PreferredEditorUnavailableError
81 >
59 > => {82 > => {
60 if (environmentId === null) {83 if (environmentId === null) {
61 return AsyncResult.failure(84 return AsyncResult.failure(
62 Cause.fail(85 Cause.fail(
63 new PreferredEditorUnavailableError({86 new PreferredEditorEnvironmentRequiredError({
64 message: "No environment is selected.",87 targetPath,
65 }),88 }),
66 ),89 ),
67 );90 );
...@@ -71,7 +94,9 @@ export function useOpenInPreferredEditor(...@@ -71,7 +94,9 @@ export function useOpenInPreferredEditor(
71 return AsyncResult.failure(94 return AsyncResult.failure(
72 Cause.fail(95 Cause.fail(
73 new PreferredEditorUnavailableError({96 new PreferredEditorUnavailableError({
74 message: "No available editors found.",97 environmentId,
98 targetPath,
99 availableEditorIds: availableEditors,
75 }),100 }),
76 ),101 ),
77 );102 );