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:
@@ -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')
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -447,6 +447,7 @@
|
||||
},
|
||||
{}
|
||||
)}
|
||||
key={`flow-inline-${$workspaceStore}-${$pathStore}-${flowModule.id}`}
|
||||
/>
|
||||
<DiffEditor
|
||||
open={false}
|
||||
|
||||
@@ -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> = {}
|
||||
|
||||
Reference in New Issue
Block a user