save editor cursor positions (#6039)

* save global css panel cursor position

* save editor cursor positions globally

* better initialCursorPos + avoid flicker

* unused var err

* editorPositionMap global

* handle cursor pos saving in editors

* better editor keys

* feat: add workspaceStore to all editor key props for better isolation

- Added workspaceStore import to InlineScriptEditor.svelte
- Updated all editor keys to include workspace prefix:
  - CssSettings: `app-global-css-editor-${$workspaceStore}-${$appPath}`
  - InlineScriptEditor: `app-inline-${$workspaceStore}-${$appPath}-${id}`
  - FlowModuleComponent: `flow-inline-${$workspaceStore}-${$pathStore}-${flowModule.id}`

This ensures cursor positions are isolated per workspace for multi-workspace scenarios.

Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>
This commit is contained in:
Diego Imbert
2025-06-24 18:42:46 +02:00
committed by GitHub
parent ba69dcf9e8
commit a2ea545b79
7 changed files with 44 additions and 16 deletions

View File

@@ -155,6 +155,7 @@
import { writable } from 'svelte/store'
import { formatResourceTypes } from './copilot/chat/script/core'
import FakeMonacoPlaceHolder from './FakeMonacoPlaceHolder.svelte'
import { editorPositionMap } from '$lib/utils'
// import EditorTheme from './EditorTheme.svelte'
let divEl: HTMLDivElement | null = null
@@ -188,6 +189,7 @@
export let extraLib: string | undefined = undefined
export let changeTimeout: number = 500
export let loadAsync = false
export let key: string | undefined = undefined
let lang = scriptLangToEditorLang(scriptLang)
$: lang = scriptLangToEditorLang(scriptLang)
@@ -1277,6 +1279,10 @@
tabSize: lang == 'python' ? 4 : 2,
folding
})
if (key && editorPositionMap?.[key]) {
editor.setPosition(editorPositionMap[key])
editor.revealPositionInCenterIfOutsideViewport(editorPositionMap[key])
}
} catch (e) {
console.error('Error loading monaco:', e)
return
@@ -1306,6 +1312,10 @@
dispatch('blur')
})
editor?.onDidChangeCursorPosition((event) => {
if (key) editorPositionMap[key] = event.position
})
editor?.onDidFocusEditorText(() => {
dispatch('focus')

View File

@@ -14,7 +14,8 @@
Uri as mUri,
languages,
type IRange,
type IDisposable
type IDisposable,
type IPosition
} from 'monaco-editor'
languages.typescript.javascriptDefaults.setCompilerOptions({
@@ -78,6 +79,7 @@
import { vimMode } from '$lib/stores'
import { initVim } from './monaco_keybindings'
import FakeMonacoPlaceHolder from './FakeMonacoPlaceHolder.svelte'
import { editorPositionMap } from '$lib/utils'
// import { createConfiguredEditor } from 'vscode/monaco'
// import type { IStandaloneCodeEditor } from 'vscode/vscode/vs/editor/standalone/browser/standaloneCodeEditor'
@@ -114,7 +116,8 @@
allowVim = false,
tailwindClasses = [],
class: className = '',
loadAsync = false
loadAsync = false,
key
}: {
lang: string
code?: string
@@ -137,6 +140,8 @@
tailwindClasses?: string[]
class?: string
loadAsync?: boolean
initialCursorPos?: IPosition
key?: string
} = $props()
const dispatch = createEventDispatcher()
@@ -380,6 +385,10 @@
snippetsPreventQuickSuggestions: disableSuggestions
}
})
if (key && editorPositionMap?.[key]) {
editor.setPosition(editorPositionMap[key])
editor.revealPositionInCenterIfOutsideViewport(editorPositionMap[key])
}
} catch (e) {
console.error('Error loading monaco:', e)
return
@@ -394,6 +403,9 @@
updateCode()
}, 200)
})
editor.onDidChangeCursorPosition((event) => {
if (key) editorPositionMap[key] = event.position
})
editor.onDidFocusEditorText(() => {
if (!editor) return

View File

@@ -13,13 +13,12 @@
import { resolveTheme } from './themeUtils'
import ThemeCodePreview from './ThemeCodePreview.svelte'
import { sendUserToast } from '$lib/toast'
const { app, appPath } = getContext<AppViewerContext>('AppViewerContext')
const { app } = getContext<AppViewerContext>('AppViewerContext')
let cssEditor: SimpleEditor | undefined = undefined
let alertHeight: number | undefined = undefined
let themeViewer: any = undefined
let selectedTab: 'css' | 'theme' = 'css'
let cssEditor: SimpleEditor | undefined = $state(undefined)
let alertHeight: number | undefined = $state(undefined)
let themeViewer: any = $state(undefined)
let selectedTab: 'css' | 'theme' = $state('css')
function insertSelector(selector: string) {
if ($app?.theme?.type === 'path') {
@@ -80,6 +79,7 @@
small
automaticLayout
bind:this={cssEditor}
key={`app-global-css-editor-${$workspaceStore}-${$appPath}`}
/>
{:else}
<ThemeCodePreview theme={$app.theme}>

View File

@@ -23,7 +23,7 @@
import DiffEditor from '$lib/components/DiffEditor.svelte'
import CacheTtlPopup from './CacheTtlPopup.svelte'
import EditorSettings from '$lib/components/EditorSettings.svelte'
import { userStore } from '$lib/stores'
import { userStore, workspaceStore } from '$lib/stores'
const {
runnableComponents,
@@ -387,6 +387,7 @@
}
$app = $app
}}
key={`app-inline-${$workspaceStore}-${$appPath}-${id}`}
args={Object.entries(fields).reduce((acc, [key, obj]) => {
acc[key] = obj.type === 'static' ? obj.value : undefined
return acc
@@ -415,6 +416,7 @@
inferSuggestions(e.detail.code)
$app = $app
}}
key={`app-inline-${$workspaceStore}-${$appPath}-${id}`}
/>
{/if}

View File

@@ -23,7 +23,7 @@ import type {
TemplateV2AppInput,
UploadAppInput,
UploadS3AppInput,
UserAppInput,
UserAppInput
} from './inputType'
import type { World } from './rx'
import type { FilledItem } from './svelte-grid/types'
@@ -141,13 +141,13 @@ export type HiddenRunnable = {
export type AppTheme =
| {
type: 'path'
path: string
}
type: 'path'
path: string
}
| {
type: 'inlined'
css: string
}
type: 'inlined'
css: string
}
export type App = {
grid: GridItem[]

View File

@@ -447,6 +447,7 @@
},
{}
)}
key={`flow-inline-${$workspaceStore}-${$pathStore}-${flowModule.id}`}
/>
<DiffEditor
open={false}

View File

@@ -1372,6 +1372,7 @@ import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import type { Snippet } from 'svelte'
import { OpenAPIV2, type OpenAPI, type OpenAPIV3, type OpenAPIV3_1 } from 'openapi-types'
import type { IPosition } from 'monaco-editor'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
@@ -1430,3 +1431,5 @@ export function scroll_into_view_if_needed_polyfill(elem: Element, centerIfNeede
return observer // return for testing
}
export const editorPositionMap: Record<string, IPosition> = {}