Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/components/src/components/sessions/session-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -664,12 +664,23 @@ const SessionDetail = ({
urlPrNumber,
urlBrowser,
onMobileBack,
hideLanguageServiceActions = false,
}: {
sessionId: SessionId;
urlTab?: string;
urlPrNumber?: number;
urlBrowser?: boolean;
onMobileBack?: () => void;
/**
* Whether the host serves a language service at all.
*
* Go to Definition and Find References are Machine RPC round trips. A host
* whose machine answers "unsupported" for every file draws two editor
* entries whose only outcome is that message, so it can take them off the
* menu instead. Passed to every file viewer this page mounts; see
* `SessionFileContentViewProps.lspAvailable`.
*/
hideLanguageServiceActions?: boolean;
}) => {
const { t } = useTranslation();
const router = useRouter();
Expand Down Expand Up @@ -4522,6 +4533,7 @@ const SessionDetail = ({
saveRequestSeq={viewerTabSaveStates[tab.id]?.saveRequestSeq ?? 0}
copyMarkdownRequestSeq={viewerTabSaveStates[tab.id]?.copyMarkdownRequestSeq ?? 0}
preferNativeMarkdownSelection={isMobile}
lspAvailable={!hideLanguageServiceActions}
fileProvider={activeSessionFileProvider}
fileProviderPending={activeSessionFileProviderPending}
fileProviderMessage={activeSessionFileProviderMessage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ export type SessionFileContentViewProps = {
* context menu. Rendered Markdown opts into native selection as well.
*/
preferNativeMarkdownSelection?: boolean;
/**
* Whether the host's machine serves a language service. With it off the two
* LSP entry points are not registered at all: Go to Definition and Find
* References leave the editor's context menu and stop answering F12 /
* Shift+F12, instead of answering every identifier with "Host language
* service does not support this file". Defaults to on.
*/
lspAvailable?: boolean;
className?: string;
active?: boolean;
fileProvider?: SessionFileProvider | null;
Expand Down Expand Up @@ -211,6 +219,7 @@ function SessionFileContentViewImpl({
saveRequestSeq,
copyMarkdownRequestSeq,
preferNativeMarkdownSelection = false,
lspAvailable = true,
className,
active = true,
fileProvider,
Expand Down Expand Up @@ -987,6 +996,7 @@ function SessionFileContentViewImpl({
// trip and exposes a small state machine the inline panel renders.
const lspFileId = providerEntry?.fileId ?? fileId ?? null;
const isLspEnabled =
lspAvailable &&
isActiveSurface &&
shouldUseProviderFileContent &&
providerEntry?.kind === 'text' &&
Expand Down Expand Up @@ -1222,6 +1232,11 @@ function SessionFileContentViewImpl({
onSelectionChange={
liveFileId !== null ? handleProviderEditorSelectionChange : undefined
}
// `lspActions` and the two callbacks answer different
// questions. The callbacks are what an action DOES; this is
// whether the action exists. An action with no callback still
// sits in the context menu and does nothing at all.
lspActions={lspAvailable}
onGoToDefinition={isLspEnabled ? handleGoToDefinition : undefined}
onFindReferences={isLspEnabled ? handleFindReferences : undefined}
externalTextUpdate={externalTextUpdate}
Expand Down Expand Up @@ -2117,6 +2132,7 @@ type SessionTextMonacoViewerProps = {
readonly line: number;
readonly character: number;
}) => void;
readonly lspActions?: boolean;
readonly externalTextUpdate?: SessionMonacoExternalTextUpdate;
readonly onExternalTextUpdateApplied?: (result: 'applied' | 'no-op') => void;
readonly findRequestSeq?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export function SessionMonacoTextViewer({
onSelectionChange,
onGoToDefinition,
onFindReferences,
lspActions = true,
onScrollChange,
externalTextUpdate,
onExternalTextUpdateApplied,
Expand Down Expand Up @@ -99,6 +100,12 @@ export function SessionMonacoTextViewer({
readonly line: number;
readonly character: number;
}) => void;
// Whether those two actions exist at all. Separate from the callbacks
// above, and read once at mount: a host whose machine serves no language
// service wants the entries OFF the context menu, and an action wired to
// an absent callback is still an entry that does nothing. Defaults to on,
// so a caller that passes neither keeps today's behaviour.
readonly lspActions?: boolean;
readonly onScrollChange?: (state: { readonly scrollTop: number }) => void;
// Optional Monaco model URI. When provided the viewer creates the
// model under this URI, which lets Monaco's globally-registered
Expand Down Expand Up @@ -139,6 +146,7 @@ export function SessionMonacoTextViewer({
readOnly,
wordWrap,
modelUri,
lspActions,
});

useEffect(() => {
Expand All @@ -153,6 +161,7 @@ export function SessionMonacoTextViewer({
initialReadOnly: initial.readOnly,
initialWordWrap: initial.wordWrap,
initialModelUri: initial.modelUri,
lspActions: initial.lspActions,
callbacks: {
onContentChange,
onSelectionChange,
Expand Down
89 changes: 49 additions & 40 deletions packages/components/src/lib/session-monaco-editor-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export type SessionMonacoEditorControllerOptions = {
readonly initialReadOnly: boolean;
readonly initialWordWrap: boolean;
readonly initialModelUri?: monaco.Uri;
/**
* Whether to register the two LSP entry-point actions at all. Off takes them
* out of the editor's context menu and unbinds F12 / Shift+F12, which is what
* a host with no language service behind the provider wants: an action whose
* callback is absent still sits in the menu and does nothing. Defaults to on.
*/
readonly lspActions?: boolean;
readonly callbacks: SessionMonacoEditorCallbacks;
};

Expand Down Expand Up @@ -179,46 +186,48 @@ export class SessionMonacoEditorController {
})
);

// LSP entry-point editor actions. Cmd-F12 / F12 fires definition;
// Shift-F12 fires references. Both pass an LSP-shape `{line, character}`
// (0-indexed) so the consumer can hand off to provider RPC directly.
// No `!editorReadonly` precondition: read roles are allowed to
// request LSP RPC by spec, so read-only viewers also surface the
// actions in the context menu.
this.disposables.push(
this.editor.addAction({
id: 'lody.codeCollab.goToDefinition',
label: 'Go to Definition (Code Collab)',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.F12, monaco.KeyCode.F12],
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.1,
run: (ed) => {
const position = ed.getPosition();
if (!position) return;
this.callbacks.onGoToDefinition?.({
line: position.lineNumber - 1,
character: position.column - 1,
});
},
})
);
this.disposables.push(
this.editor.addAction({
id: 'lody.codeCollab.findReferences',
label: 'Find References (Code Collab)',
keybindings: [monaco.KeyMod.Shift | monaco.KeyCode.F12],
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.2,
run: (ed) => {
const position = ed.getPosition();
if (!position) return;
this.callbacks.onFindReferences?.({
line: position.lineNumber - 1,
character: position.column - 1,
});
},
})
);
if (options.lspActions !== false) {
// LSP entry-point editor actions. Cmd-F12 / F12 fires definition;
// Shift-F12 fires references. Both pass an LSP-shape `{line, character}`
// (0-indexed) so the consumer can hand off to provider RPC directly.
// No `!editorReadonly` precondition: read roles are allowed to
// request LSP RPC by spec, so read-only viewers also surface the
// actions in the context menu.
this.disposables.push(
this.editor.addAction({
id: 'lody.codeCollab.goToDefinition',
label: 'Go to Definition (Code Collab)',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.F12, monaco.KeyCode.F12],
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.1,
run: (ed) => {
const position = ed.getPosition();
if (!position) return;
this.callbacks.onGoToDefinition?.({
line: position.lineNumber - 1,
character: position.column - 1,
});
},
})
);
this.disposables.push(
this.editor.addAction({
id: 'lody.codeCollab.findReferences',
label: 'Find References (Code Collab)',
keybindings: [monaco.KeyMod.Shift | monaco.KeyCode.F12],
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.2,
run: (ed) => {
const position = ed.getPosition();
if (!position) return;
this.callbacks.onFindReferences?.({
line: position.lineNumber - 1,
character: position.column - 1,
});
},
})
);
}
}

// Swap the callback bundle. Listeners read `this.callbacks` at fire
Expand Down