mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
Fix Monaco Peek References preview collapse (#7662)
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -1971,6 +1971,16 @@
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Why: Monaco leaves the peek preview container `inline-block` and only sizes the
|
||||
editor child, so the container shrink-wraps the child in BOTH axes while the
|
||||
inherited automaticLayout ResizeObserver measures the container — a feedback
|
||||
loop that ratchets the preview to blank at fractional zoom/DPI (issue #7405).
|
||||
Pinning both dimensions to the splitview slot severs the loop. */
|
||||
.monaco-editor .reference-zone-widget .preview.inline {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ── Git conflict decorations ───────────────────────────────────── */
|
||||
|
||||
.monaco-editor .orca-conflict-marker-line {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type * as Monaco from 'monaco-editor'
|
||||
import { installMonacoPeekReferencesPreviewOptions } from './monaco-peek-preview-options'
|
||||
|
||||
type FakePreviewEditor = Pick<Monaco.editor.ICodeEditor, 'updateOptions'>
|
||||
|
||||
type FakeReferenceWidgetInstance = {
|
||||
_preview?: FakePreviewEditor
|
||||
_fillBody?: (containerElement: HTMLElement) => void
|
||||
_revealReference?: (...args: unknown[]) => Promise<unknown>
|
||||
}
|
||||
|
||||
function createReferenceWidgetConstructor(hooks: {
|
||||
fillBody?: (instance: FakeReferenceWidgetInstance) => void
|
||||
revealReference?: (instance: FakeReferenceWidgetInstance) => Promise<unknown>
|
||||
}): {
|
||||
prototype: FakeReferenceWidgetInstance &
|
||||
Required<Pick<FakeReferenceWidgetInstance, '_fillBody' | '_revealReference'>>
|
||||
} {
|
||||
return {
|
||||
prototype: {
|
||||
_fillBody(this: FakeReferenceWidgetInstance): void {
|
||||
hooks.fillBody?.(this)
|
||||
},
|
||||
async _revealReference(this: FakeReferenceWidgetInstance): Promise<unknown> {
|
||||
return hooks.revealReference?.(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createPreviewEditor(): FakePreviewEditor {
|
||||
return { updateOptions: vi.fn() }
|
||||
}
|
||||
|
||||
const peekPreviewOptions = {
|
||||
smoothScrolling: false,
|
||||
stickyScroll: { enabled: false },
|
||||
wordWrap: 'off'
|
||||
}
|
||||
|
||||
describe('installMonacoPeekReferencesPreviewOptions', () => {
|
||||
it('updates the embedded preview after ReferenceWidget creates it', () => {
|
||||
const preview = createPreviewEditor()
|
||||
const referenceWidget = createReferenceWidgetConstructor({
|
||||
fillBody(instance) {
|
||||
instance._preview = preview
|
||||
}
|
||||
})
|
||||
|
||||
installMonacoPeekReferencesPreviewOptions(referenceWidget)
|
||||
referenceWidget.prototype._fillBody(document.createElement('div'))
|
||||
|
||||
expect(preview.updateOptions).toHaveBeenCalledWith(peekPreviewOptions)
|
||||
})
|
||||
|
||||
it('updates the embedded preview before revealing a reference', async () => {
|
||||
const calls: string[] = []
|
||||
const preview: FakePreviewEditor = {
|
||||
updateOptions: vi.fn(() => calls.push('updateOptions'))
|
||||
}
|
||||
const referenceWidget = createReferenceWidgetConstructor({
|
||||
revealReference: async () => {
|
||||
calls.push('revealReference')
|
||||
}
|
||||
})
|
||||
referenceWidget.prototype._preview = preview
|
||||
|
||||
installMonacoPeekReferencesPreviewOptions(referenceWidget)
|
||||
await referenceWidget.prototype._revealReference('reference')
|
||||
|
||||
expect(calls).toEqual(['updateOptions', 'revealReference', 'updateOptions'])
|
||||
expect(preview.updateOptions).toHaveBeenCalledWith(peekPreviewOptions)
|
||||
})
|
||||
|
||||
it('skips patching when the private Monaco hooks are missing', () => {
|
||||
const referenceWidget: { prototype: FakeReferenceWidgetInstance } = { prototype: {} }
|
||||
|
||||
installMonacoPeekReferencesPreviewOptions(referenceWidget)
|
||||
|
||||
expect(referenceWidget.prototype._fillBody).toBeUndefined()
|
||||
expect(referenceWidget.prototype._revealReference).toBeUndefined()
|
||||
})
|
||||
|
||||
it('does not wrap ReferenceWidget more than once', async () => {
|
||||
const preview = createPreviewEditor()
|
||||
const referenceWidget = createReferenceWidgetConstructor({})
|
||||
referenceWidget.prototype._preview = preview
|
||||
|
||||
installMonacoPeekReferencesPreviewOptions(referenceWidget)
|
||||
installMonacoPeekReferencesPreviewOptions(referenceWidget)
|
||||
await referenceWidget.prototype._revealReference('reference')
|
||||
|
||||
expect(preview.updateOptions).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,67 @@
|
||||
import type * as Monaco from 'monaco-editor'
|
||||
import { ReferenceWidget as MonacoReferenceWidget } from 'monaco-editor/esm/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.js'
|
||||
|
||||
type PeekPreviewEditor = Pick<Monaco.editor.ICodeEditor, 'updateOptions'>
|
||||
|
||||
const PEEK_REFERENCES_PREVIEW_OPTIONS: Monaco.editor.IEditorOptions = {
|
||||
smoothScrolling: false,
|
||||
stickyScroll: { enabled: false },
|
||||
wordWrap: 'off'
|
||||
}
|
||||
|
||||
type ReferenceWidgetInstance = {
|
||||
_preview?: PeekPreviewEditor
|
||||
_fillBody?: (containerElement: HTMLElement) => void
|
||||
_revealReference?: (...args: unknown[]) => Promise<unknown>
|
||||
}
|
||||
|
||||
type ReferenceWidgetConstructor = {
|
||||
prototype: ReferenceWidgetInstance & {
|
||||
__orcaPeekPreviewOptionsInstalled?: true
|
||||
}
|
||||
}
|
||||
|
||||
function applyPeekReferencesPreviewOptions(editor: PeekPreviewEditor | undefined): void {
|
||||
// Why: Monaco embedded editors inherit Orca's full-editor options first.
|
||||
// Peek previews are transient readers, so keep scroll/wrap widgets out of them.
|
||||
editor?.updateOptions(PEEK_REFERENCES_PREVIEW_OPTIONS)
|
||||
}
|
||||
|
||||
export function installMonacoPeekReferencesPreviewOptions(
|
||||
referenceWidget: ReferenceWidgetConstructor = MonacoReferenceWidget as unknown as ReferenceWidgetConstructor
|
||||
): void {
|
||||
const prototype = referenceWidget.prototype
|
||||
if (prototype.__orcaPeekPreviewOptionsInstalled) {
|
||||
return
|
||||
}
|
||||
|
||||
const originalFillBody = prototype._fillBody
|
||||
const originalRevealReference = prototype._revealReference
|
||||
// Why: these are private Monaco members with no stability guarantee; if an
|
||||
// upgrade removes either, skip patching so Peek keeps Monaco's defaults.
|
||||
if (typeof originalFillBody !== 'function' || typeof originalRevealReference !== 'function') {
|
||||
return
|
||||
}
|
||||
|
||||
prototype._fillBody = function fillBodyWithPeekPreviewOptions(
|
||||
this: ReferenceWidgetInstance,
|
||||
containerElement: HTMLElement
|
||||
): void {
|
||||
originalFillBody.call(this, containerElement)
|
||||
applyPeekReferencesPreviewOptions(this._preview)
|
||||
}
|
||||
|
||||
prototype._revealReference = async function revealReferenceWithPeekPreviewOptions(
|
||||
this: ReferenceWidgetInstance,
|
||||
...args: unknown[]
|
||||
): Promise<unknown> {
|
||||
applyPeekReferencesPreviewOptions(this._preview)
|
||||
try {
|
||||
return await originalRevealReference.apply(this, args)
|
||||
} finally {
|
||||
applyPeekReferencesPreviewOptions(this._preview)
|
||||
}
|
||||
}
|
||||
|
||||
prototype.__orcaPeekPreviewOptionsInstalled = true
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { registerSvelteLanguage } from './monaco-languages/register-svelte'
|
||||
import { registerVueLanguage } from './monaco-languages/register-vue'
|
||||
import { installMonacoDelayerCancellationGuard } from './monaco-delayer-cancellation-guard'
|
||||
import { installMonacoDiffEditorDisposalGuard } from './monaco-diff-editor-disposal'
|
||||
import { installMonacoPeekReferencesPreviewOptions } from './monaco-peek-preview-options'
|
||||
import { installMonacoContextMenuPaste } from '@/components/editor/install-monaco-context-menu-paste'
|
||||
|
||||
globalThis.MonacoEnvironment = {
|
||||
@@ -78,6 +79,7 @@ registerAstroLanguage(monaco)
|
||||
registerNimLanguage(monaco)
|
||||
installMonacoDelayerCancellationGuard()
|
||||
installMonacoDiffEditorDisposalGuard(monaco)
|
||||
installMonacoPeekReferencesPreviewOptions()
|
||||
// Why: Monaco's built-in context-menu Paste reads navigator.clipboard, which is
|
||||
// blocked in Orca's sandboxed renderer. Route it through the trusted IPC bridge
|
||||
// so right-click Paste works like Cmd+V (which already works via native events).
|
||||
|
||||
Reference in New Issue
Block a user