Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into jupyterlabgh-15661-…
Browse files Browse the repository at this point in the history
…mermaid-1080
  • Loading branch information
bollwyvl committed Dec 12, 2024
2 parents 78582d7 + f85b838 commit 87a954d
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 14 deletions.
28 changes: 26 additions & 2 deletions galata/test/jupyterlab/inline-completer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const SHORTCUTS_ID = '@jupyterlab/shortcuts-extension:shortcuts';
const SHARED_SETTINGS = {
providers: {
'@jupyterlab/inline-completer:history': {
enabled: true
enabled: true,
autoFillInMiddle: true
}
}
};
Expand Down Expand Up @@ -231,7 +232,7 @@ test.describe('Inline Completer', () => {
});

test('Ghost text updates on typing', async ({ page }) => {
const cellEditor = await page.notebook.getCellInputLocator(2);
const cellEditor = (await page.notebook.getCellInputLocator(2))!;
await page.keyboard.press('u');

// Ghost text shows up
Expand All @@ -251,6 +252,29 @@ test.describe('Inline Completer', () => {
await expect(ghostText).toBeHidden();
});

test('Ghost text shows on middle of line when FIM is enabled', async ({
page
}) => {
const cellEditor = (await page.notebook.getCellInputLocator(2))!;
await page.keyboard.press('u');

// Ghost text shows up
const ghostText = cellEditor.locator(GHOST_SELECTOR);
await ghostText.waitFor();

await page.keyboard.type('n'); //sun|
await page.keyboard.press('ArrowLeft'); //su|n
await page.keyboard.type('g'); //sug|n
await expect(ghostText).toHaveText('gestio'); //sug|(gestio)n
await page.keyboard.press('ArrowRight'); //sugn|
await page.keyboard.press('Backspace'); //sug|
await page.keyboard.type('q'); //sugq|
await page.keyboard.press('ArrowLeft'); //sug|q
await page.keyboard.press('Backspace'); //su|q
await page.keyboard.type('g'); //sug|q
await expect(ghostText).toBeHidden(); //Hidden on sug|q
});

test('Empty space is retained to avoid jitter', async ({ page }) => {
const cellEditor = (await page.notebook.getCellInputLocator(2))!;
const measureEditorHeight = async () =>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions packages/completer-extension/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ const inlineCompleter: JupyterFrontEndPlugin<void> = {
// By default all providers are opt-out, but
// any provider can configure itself to be opt-in.
enabled: true,
autoFillInMiddle: false,
timeout: 5000,
debouncerDelay: 0,
...((provider.schema?.default as object) ?? {})
Expand Down Expand Up @@ -316,6 +317,14 @@ const inlineCompleter: JupyterFrontEndPlugin<void> = {
provider.name
),
type: 'boolean'
},
autoFillInMiddle: {
title: trans.__('Fill in middle on typing'),
description: trans.__(
'Whether to show completions in the middle of the code line from %1 provider on typing.',
provider.name
),
type: 'boolean'
}
},
default: composeDefaults(provider),
Expand Down
18 changes: 12 additions & 6 deletions packages/completer/src/default/inlinehistoryprovider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class HistoryInlineCompletionProvider

const multiLinePrefix = request.text.slice(0, request.offset);
const linePrefix = multiLinePrefix.split('\n').slice(-1)[0];

const suffix = request.text.slice(request.offset).split('\n')[0];
let historyRequest: KernelMessage.IHistoryRequestMsg['content'];

const items = [];
Expand Down Expand Up @@ -117,7 +117,7 @@ export class HistoryInlineCompletionProvider
output: false,
raw: true,
hist_access_type: 'search',
pattern: linePrefix + '*',
pattern: linePrefix + '*' + (suffix ? suffix + '*' : ''),
unique: true,
n: this._maxSuggestions
};
Expand All @@ -129,10 +129,16 @@ export class HistoryInlineCompletionProvider
for (let i = 0; i < sourceLines.length; i++) {
const line = sourceLines[i];
if (line.startsWith(linePrefix)) {
const followingLines =
line.slice(linePrefix.length, line.length) +
'\n' +
sourceLines.slice(i + 1).join('\n');
let followingLines = line.slice(linePrefix.length);
if (i + 1 < sourceLines.length) {
followingLines += '\n' + sourceLines.slice(i + 1).join('\n');
}
if (suffix) {
followingLines = followingLines.slice(
0,
followingLines.indexOf(suffix)
);
}
items.push({
insertText: followingLines
});
Expand Down
13 changes: 11 additions & 2 deletions packages/completer/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,6 @@ export class CompletionHandler implements IDisposable {
if (
trigger === InlineCompletionTriggerKind.Automatic &&
(typeof line === 'undefined' ||
position.column < line.length ||
line.slice(0, position.column).match(/^\s*$/))
) {
// In Automatic mode we only auto-trigger on the end of line (and not on the beginning).
Expand All @@ -476,6 +475,12 @@ export class CompletionHandler implements IDisposable {
return;
}

let isMiddleOfLine = false;

if (typeof line !== 'undefined' && position.column < line.length) {
isMiddleOfLine = true;
}

const request = this._composeRequest(editor, position);

const model = this.inlineCompleter.model;
Expand All @@ -485,7 +490,11 @@ export class CompletionHandler implements IDisposable {
model.cursor = position;

const current = ++this._fetchingInline;
const promises = this._reconciliator.fetchInline(request, trigger);
const promises = this._reconciliator.fetchInline(
request,
trigger,
isMiddleOfLine
);
let cancelled = false;

const completed = new Set<
Expand Down
12 changes: 10 additions & 2 deletions packages/completer/src/reconciliator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,23 @@ export class ProviderReconciliator implements IProviderReconciliator {

fetchInline(
request: CompletionHandler.IRequest,
trigger: InlineCompletionTriggerKind
trigger: InlineCompletionTriggerKind,
isMiddleOfLine?: boolean
): Promise<InlineResult>[] {
let promises: Promise<
IInlineCompletionList<CompletionHandler.IInlineItem>
>[] = [];
const current = ++this._inlineFetching;
for (const provider of this._inlineProviders) {
const settings = this._inlineProvidersSettings[provider.identifier];

if (
trigger !== InlineCompletionTriggerKind.Invoke &&
isMiddleOfLine &&
!settings.autoFillInMiddle
) {
// Skip if FIM is disabled
continue;
}
let delay = 0;
if (trigger === InlineCompletionTriggerKind.Automatic) {
delay = settings.debouncerDelay;
Expand Down
4 changes: 3 additions & 1 deletion packages/completer/src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ export interface IInlineCompleterSettings {
providers: {
[providerId: string]: {
enabled: boolean;
autoFillInMiddle: boolean;
debouncerDelay: number;
timeout: number;
[property: string]: JSONValue;
Expand Down Expand Up @@ -524,7 +525,8 @@ export interface IProviderReconciliator {
*/
fetchInline(
request: CompletionHandler.IRequest,
trigger?: InlineCompletionTriggerKind
trigger?: InlineCompletionTriggerKind,
isMiddleOfLine?: boolean
): Promise<IInlineCompletionList<CompletionHandler.IInlineItem> | null>[];

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/metapackage/test/completer/manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ describe('completer/manager', () => {

const sharedConfig = {
debouncerDelay: 0,
timeout: 10000
timeout: 10000,
autoFillInMiddle: false
};
inline.configure({
providers: {
Expand Down

0 comments on commit 87a954d

Please sign in to comment.