Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153import { createEffect, createRoot } from "solid-js"import { produce } from "solid-js/store"import { Schema } from "effect"import { Persist, persisted } from "@/runtime/persistence/storage"import { Persistence } from "@/runtime/persistence/schema"import { createScopedCache } from "@/runtime/server/scoped-cache"import { SelectedLineRange } from "./types"import type { ServerScope } from "@/runtime/server/scope"
const WORKSPACE_KEY = "__workspace__"const MAX_FILE_VIEW_SESSIONS = 20const MAX_VIEW_FILES = 500
const FileViewSchema = Persistence.struct({ scrollTop: Persistence.optional(Schema.Finite), scrollLeft: Persistence.optional(Schema.Finite), selectedLines: Persistence.optional(Schema.NullOr(SelectedLineRange)),})
export const FileViewsSchema = Schema.Struct({ file: Persistence.record(Persistence.fallback(FileViewSchema, () => ({}))),})
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 [view, setView, _, ready] = persisted(Persist.serverScoped(scope, dir, id, "file-view"), FileViewsSchema, { 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(), }}