Buckets:
| import { createEffect, createRoot } from "solid-js" | |
| import { createStore, produce } from "solid-js/store" | |
| import { Persist, persisted } from "@/utils/persist" | |
| import { createScopedCache } from "@/utils/scoped-cache" | |
| import type { FileViewState, SelectedLineRange } from "./types" | |
| import type { ServerScope } from "@/utils/server-scope" | |
| const WORKSPACE_KEY = "__workspace__" | |
| const MAX_FILE_VIEW_SESSIONS = 20 | |
| const MAX_VIEW_FILES = 500 | |
| function normalizeSelectedLines(range: SelectedLineRange): SelectedLineRange { | |
| if (range.start <= range.end) return { ...range } | |
| const startSide = range.side | |
| const endSide = range.endSide ?? startSide | |
| return { | |
| ...range, | |
| start: range.end, | |
| end: range.start, | |
| side: endSide, | |
| endSide: startSide !== endSide ? startSide : undefined, | |
| } | |
| } | |
| function equalSelectedLines(a: SelectedLineRange | null | undefined, b: SelectedLineRange | null | undefined) { | |
| if (!a && !b) return true | |
| if (!a || !b) return false | |
| const left = normalizeSelectedLines(a) | |
| const right = normalizeSelectedLines(b) | |
| return ( | |
| left.start === right.start && left.end === right.end && left.side === right.side && left.endSide === right.endSide | |
| ) | |
| } | |
| function createViewSession(scope: ServerScope, dir: string, id: string | undefined) { | |
| const legacyViewKey = `${dir}/file${id ? "/" + id : ""}.v1` | |
| const [view, setView, _, ready] = persisted( | |
| Persist.serverScoped(scope, dir, id, "file-view", [legacyViewKey]), | |
| createStore<{ | |
| file: Record<string, FileViewState> | |
| }>({ | |
| file: {}, | |
| }), | |
| ) | |
| const meta = { pruned: false } | |
| const pruneView = (keep?: string) => { | |
| const keys = Object.keys(view.file) | |
| if (keys.length <= MAX_VIEW_FILES) return | |
| const drop = keys.filter((key) => key !== keep).slice(0, keys.length - MAX_VIEW_FILES) | |
| if (drop.length === 0) return | |
| setView( | |
| produce((draft) => { | |
| for (const key of drop) { | |
| delete draft.file[key] | |
| } | |
| }), | |
| ) | |
| } | |
| createEffect(() => { | |
| if (!ready()) return | |
| if (meta.pruned) return | |
| meta.pruned = true | |
| pruneView() | |
| }) | |
| const scrollTop = (path: string) => view.file[path]?.scrollTop | |
| const scrollLeft = (path: string) => view.file[path]?.scrollLeft | |
| const selectedLines = (path: string) => view.file[path]?.selectedLines | |
| const setScrollTop = (path: string, top: number) => { | |
| setView( | |
| produce((draft) => { | |
| const file = draft.file[path] ?? (draft.file[path] = {}) | |
| if (file.scrollTop === top) return | |
| file.scrollTop = top | |
| }), | |
| ) | |
| pruneView(path) | |
| } | |
| const setScrollLeft = (path: string, left: number) => { | |
| setView( | |
| produce((draft) => { | |
| const file = draft.file[path] ?? (draft.file[path] = {}) | |
| if (file.scrollLeft === left) return | |
| file.scrollLeft = left | |
| }), | |
| ) | |
| pruneView(path) | |
| } | |
| const setSelectedLines = (path: string, range: SelectedLineRange | null) => { | |
| const next = range ? normalizeSelectedLines(range) : null | |
| setView( | |
| produce((draft) => { | |
| const file = draft.file[path] ?? (draft.file[path] = {}) | |
| if (equalSelectedLines(file.selectedLines, next)) return | |
| file.selectedLines = next | |
| }), | |
| ) | |
| pruneView(path) | |
| } | |
| return { | |
| ready, | |
| scrollTop, | |
| scrollLeft, | |
| selectedLines, | |
| setScrollTop, | |
| setScrollLeft, | |
| setSelectedLines, | |
| } | |
| } | |
| export function createFileViewCache(scope: ServerScope) { | |
| const cache = createScopedCache( | |
| (key) => { | |
| const split = key.lastIndexOf("\n") | |
| const dir = split >= 0 ? key.slice(0, split) : key | |
| const id = split >= 0 ? key.slice(split + 1) : WORKSPACE_KEY | |
| return createRoot((dispose) => ({ | |
| value: createViewSession(scope, dir, id === WORKSPACE_KEY ? undefined : id), | |
| dispose, | |
| })) | |
| }, | |
| { | |
| maxEntries: MAX_FILE_VIEW_SESSIONS, | |
| dispose: (entry) => entry.dispose(), | |
| }, | |
| ) | |
| return { | |
| load: (dir: string, id: string | undefined) => { | |
| const key = `${dir}\n${id ?? WORKSPACE_KEY}` | |
| return cache.get(key).value | |
| }, | |
| clear: () => cache.clear(), | |
| } | |
| } | |
Xet Storage Details
- Size:
- 4.12 kB
- Xet hash:
- 31f87bdbeacf8318e08c80ec43b7b47c652c868502f107ffa2c2e023d7d5befe
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.