Skip to content

Commit df3ba6c

Browse files
samiyacDevtools-frontend LUCI CQ
authored andcommitted
Move logic for instantiating AI completion provider to StylesSidebarPane
This is required for adding code completion summary toolbar (which contains loading state, privacy disclaimer etc.) Bug: 476101419, 476101019 Change-Id: I26fb4de4ae353991d7346059491b5beb2d1d4af3 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7686276 Reviewed-by: Philip Pfaffe <pfaffe@chromium.org> Auto-Submit: Samiya Caur <samiyac@chromium.org> Commit-Queue: Samiya Caur <samiyac@chromium.org>
1 parent 0cd5795 commit df3ba6c

5 files changed

Lines changed: 77 additions & 67 deletions

File tree

front_end/panels/elements/StylesAiCodeCompletionProvider.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function createProvider(): {
1616
provider: Elements.StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider,
1717
config: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig,
1818
} {
19-
const config = {
19+
const config: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig = {
2020
panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
2121
completionContext: {},
2222
generationContext: {},
@@ -25,11 +25,10 @@ function createProvider(): {
2525
onSuggestionAccepted: () => {},
2626
onRequestTriggered: () => {},
2727
onResponseReceived: () => {},
28-
getCompletionHint: () => null,
29-
getCurrentText: () => '',
30-
setAiAutoCompletion: () => {},
3128
};
3229
const provider = Elements.StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(config);
30+
provider.getCompletionHint = () => null;
31+
provider.setAiAutoCompletion = () => {};
3332
return {provider, config};
3433
}
3534

@@ -140,7 +139,7 @@ describeWithEnvironment('StylesAiCodeCompletionProvider', () => {
140139
fromCache: false,
141140
});
142141
const {provider, config} = createProvider();
143-
const setAiAutoCompletionSpy = sinon.spy(config, 'setAiAutoCompletion');
142+
const setAiAutoCompletionSpy = sinon.spy(provider, 'setAiAutoCompletion');
144143
const onRequestTriggeredSpy = sinon.spy(config, 'onRequestTriggered');
145144
const onResponseReceivedSpy = sinon.spy(config, 'onResponseReceived');
146145
const {cssModel, cssProperty} = createCssModelAndProperty();

front_end/panels/elements/StylesAiCodeCompletionProvider.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ export class StylesAiCodeCompletionProvider {
1616
#aiCodeCompletion?: AiCodeCompletion.AiCodeCompletion.AiCodeCompletion;
1717
#aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
1818

19+
getCompletionHint?: () => string | null;
20+
setAiAutoCompletion?: (args: {
21+
text: string,
22+
from: number,
23+
startTime: number,
24+
onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
25+
clearCachedRequest: () => void,
26+
rpcGlobalId?: Host.AidaClient.RpcGlobalId,
27+
sampleId?: number,
28+
}|null) => void;
29+
1930
#boundOnUpdateAiCodeCompletionState = this.#updateAiCodeCompletionState.bind(this);
2031

2132
private constructor(aiCodeCompletionConfig: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig) {
@@ -123,7 +134,7 @@ export class StylesAiCodeCompletionProvider {
123134
return;
124135
}
125136

126-
this.#aiCodeCompletionConfig?.setAiAutoCompletion?.({
137+
this.setAiAutoCompletion?.({
127138
text: currentPropertyString + aidaSuggestion.suggestionText,
128139
from: cursorPosition,
129140
rpcGlobalId: aidaSuggestion.rpcGlobalId,
@@ -206,7 +217,7 @@ export class StylesAiCodeCompletionProvider {
206217
return null;
207218
}
208219

209-
const completionHint = this.#aiCodeCompletionConfig?.getCompletionHint?.();
220+
const completionHint = this.getCompletionHint?.();
210221
if (!completionHint) {
211222
return response.generatedSamples[0];
212223
}

front_end/panels/elements/StylesSidebarPane.test.ts

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import * as Host from '../../core/host/host.js';
56
import * as SDK from '../../core/sdk/sdk.js';
67
import * as Protocol from '../../generated/protocol.js';
78
import * as ComputedStyle from '../../models/computed_style/computed_style.js';
@@ -35,6 +36,11 @@ describe('StylesSidebarPane', () => {
3536
const target = createTarget();
3637
const cssModel = target.model(SDK.CSSModel.CSSModel);
3738
sinon.stub(ComputedStyle.ComputedStyleModel.ComputedStyleModel.prototype, 'cssModel').returns(cssModel);
39+
sinon.stub(Host.AidaClient.HostConfigTracker, 'instance').returns({
40+
addEventListener: () => {},
41+
removeEventListener: () => {},
42+
dispose: () => {},
43+
} as unknown as Host.AidaClient.HostConfigTracker);
3844
});
3945

4046
it('unescapes CSS strings', () => {
@@ -1241,6 +1247,8 @@ describe('StylesSidebarPane', () => {
12411247
'--wide-gamut-color': 'lch(0 0 0)',
12421248
};
12431249

1250+
let aiCodeCompletionProvider:
1251+
sinon.SinonStubbedInstance<Elements.StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider>;
12441252
let section: sinon.SinonStubbedInstance<Elements.StylePropertiesSection.StylePropertiesSection>;
12451253
let mockTreeItem: Elements.StylePropertyTreeElement.StylePropertyTreeElement;
12461254

@@ -1298,6 +1306,9 @@ describe('StylesSidebarPane', () => {
12981306
const pane = sinon.createStubInstance(Elements.StylesSidebarPane.StylesSidebarPane);
12991307
const cssModel = sinon.createStubInstance(SDK.CSSModel.CSSModel);
13001308
pane.cssModel.returns(cssModel);
1309+
aiCodeCompletionProvider =
1310+
sinon.createStubInstance(Elements.StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider);
1311+
pane.aiCodeCompletionProvider = aiCodeCompletionProvider;
13011312
return pane;
13021313
}
13031314
} as unknown as Elements.StylePropertyTreeElement.StylePropertyTreeElement;
@@ -1382,8 +1393,6 @@ describe('StylesSidebarPane', () => {
13821393
});
13831394

13841395
describe('AI code completion', () => {
1385-
let aiCodeCompletionProvider:
1386-
sinon.SinonStubbedInstance<Elements.StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider>;
13871396
let attachedElement: HTMLDivElement;
13881397
let cssPropertyPrompt: Elements.StylesSidebarPane.CSSPropertyPrompt;
13891398

@@ -1399,11 +1408,6 @@ describe('StylesSidebarPane', () => {
13991408
}
14001409
});
14011410

1402-
aiCodeCompletionProvider =
1403-
sinon.createStubInstance(Elements.StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider);
1404-
sinon.stub(Elements.StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider, 'createInstance')
1405-
.returns(aiCodeCompletionProvider);
1406-
14071411
attachedElement = document.createElement('div');
14081412
renderElementIntoDOM(attachedElement);
14091413
cssPropertyPrompt = new Elements.StylesSidebarPane.CSSPropertyPrompt(mockTreeItem, false);
@@ -1412,21 +1416,21 @@ describe('StylesSidebarPane', () => {
14121416
it('getCompletionHint returns null if suggestBox is not visible', () => {
14131417
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
14141418

1415-
assert.exists(cssPropertyPrompt.aiCodeCompletionConfig);
1416-
assert.exists(cssPropertyPrompt.aiCodeCompletionConfig.getCompletionHint);
1417-
assert.isNull(cssPropertyPrompt.aiCodeCompletionConfig.getCompletionHint());
1419+
assert.exists(cssPropertyPrompt.aiCodeCompletionProvider?.getCompletionHint);
1420+
assert.isNull(cssPropertyPrompt.aiCodeCompletionProvider.getCompletionHint());
14181421
});
14191422

14201423
it('getCompletionHint returns the correct completion hint', async () => {
14211424
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
14221425
cssPropertyPrompt.setText('var(--rgb');
14231426
await cssPropertyPrompt.complete(true);
14241427

1425-
assert.strictEqual(cssPropertyPrompt.aiCodeCompletionConfig?.getCompletionHint?.(), '-color)');
1428+
assert.strictEqual(cssPropertyPrompt.aiCodeCompletionProvider?.getCompletionHint?.(), '-color)');
14261429
});
14271430

14281431
it('debounces triggerAiCodeCompletion', async () => {
14291432
const clock = sinon.useFakeTimers();
1433+
const triggerAiCodeCompletionStub = aiCodeCompletionProvider.triggerAiCodeCompletion.resolves();
14301434
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
14311435

14321436
cssPropertyPrompt.setText('backgr');
@@ -1437,30 +1441,31 @@ describe('StylesSidebarPane', () => {
14371441
cssPropertyPrompt.onInput(new Event('input'));
14381442
await clock.tickAsync(TextEditor.AiCodeCompletionProvider.AIDA_REQUEST_DEBOUNCE_TIMEOUT_MS + 1);
14391443

1440-
sinon.assert.calledOnce(aiCodeCompletionProvider.triggerAiCodeCompletion);
1441-
assert.strictEqual(aiCodeCompletionProvider.triggerAiCodeCompletion.firstCall.args[0], 'backgrou');
1442-
assert.strictEqual(aiCodeCompletionProvider.triggerAiCodeCompletion.firstCall.args[1], 8);
1444+
sinon.assert.calledOnce(triggerAiCodeCompletionStub);
1445+
assert.strictEqual(triggerAiCodeCompletionStub.firstCall.args[0], 'backgrou');
1446+
assert.strictEqual(triggerAiCodeCompletionStub.firstCall.args[1], 8);
14431447
clock.restore();
14441448
});
14451449

14461450
it('triggerAiCodeCompletion calls the provider with correct arguments', () => {
14471451
const clock = sinon.useFakeTimers();
1452+
const triggerAiCodeCompletionStub = aiCodeCompletionProvider.triggerAiCodeCompletion.resolves();
14481453
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
14491454

14501455
cssPropertyPrompt.setText('backgrou');
14511456
cssPropertyPrompt.onInput(new Event('input'));
14521457
clock.tick(TextEditor.AiCodeCompletionProvider.AIDA_REQUEST_DEBOUNCE_TIMEOUT_MS + 1);
14531458

1454-
sinon.assert.calledOnce(aiCodeCompletionProvider.triggerAiCodeCompletion);
1455-
assert.strictEqual(aiCodeCompletionProvider.triggerAiCodeCompletion.firstCall.args[0], 'backgrou');
1456-
assert.strictEqual(aiCodeCompletionProvider.triggerAiCodeCompletion.firstCall.args[1], 8);
1459+
sinon.assert.calledOnce(triggerAiCodeCompletionStub);
1460+
assert.strictEqual(triggerAiCodeCompletionStub.firstCall.args[0], 'backgrou');
1461+
assert.strictEqual(triggerAiCodeCompletionStub.firstCall.args[1], 8);
14571462
clock.restore();
14581463
});
14591464

14601465
it('setAiAutoCompletion sets activeAiSuggestion on the section', async () => {
14611466
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
14621467

1463-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1468+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
14641469
text: 'color: pink;',
14651470
from: 0,
14661471
startTime: 0,
@@ -1481,7 +1486,7 @@ content: "This is a semicolon; and this is a colon: inside a string";
14811486
width: calc(100% - 20px);
14821487
color: pink !important;`;
14831488

1484-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1489+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
14851490
text: complexCss,
14861491
from: 0,
14871492
startTime: 0,
@@ -1503,7 +1508,7 @@ color: pink !important;`;
15031508
cssPropertyPrompt.setText('var(--rgb');
15041509
await cssPropertyPrompt.complete(true);
15051510

1506-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1511+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
15071512
text: 'color: var(--rgb-color);',
15081513
from: 0,
15091514
startTime: 0,
@@ -1524,7 +1529,7 @@ color: pink !important;`;
15241529
cssPropertyPrompt.setText('var(--rgb');
15251530
await cssPropertyPrompt.complete(true);
15261531

1527-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1532+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
15281533
text: 'color: var(--rgb-color);',
15291534
from: 0,
15301535
startTime: 0,
@@ -1546,7 +1551,7 @@ color: pink !important;`;
15461551
cssPropertyPrompt = new Elements.StylesSidebarPane.CSSPropertyPrompt(mockTreeItem, true);
15471552
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
15481553

1549-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1554+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
15501555
text: 'color: pink;',
15511556
from: 0,
15521557
startTime: 0,
@@ -1566,7 +1571,7 @@ color: pink !important;`;
15661571

15671572
cssPropertyPrompt.setText('gre');
15681573
await cssPropertyPrompt.complete(true);
1569-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1574+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
15701575
text: 'color: greenyellow;',
15711576
from: 0,
15721577
startTime: 0,
@@ -1590,7 +1595,7 @@ color: pink !important;`;
15901595

15911596
cssPropertyPrompt.setText('var(--rgb');
15921597
await cssPropertyPrompt.complete(true);
1593-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1598+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
15941599
text: 'color: var(--rgb-color); background-color: white;',
15951600
from: 0,
15961601
startTime: 0,
@@ -1616,8 +1621,8 @@ color: pink !important;`;
16161621
it('clears suggestion if user input does not match', async () => {
16171622
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
16181623

1619-
assert.exists(cssPropertyPrompt.aiCodeCompletionConfig);
1620-
cssPropertyPrompt.aiCodeCompletionConfig.setAiAutoCompletion?.({
1624+
assert.exists(cssPropertyPrompt.aiCodeCompletionProvider);
1625+
cssPropertyPrompt.aiCodeCompletionProvider.setAiAutoCompletion?.({
16211626
text: 'color: pink;',
16221627
from: 0,
16231628
startTime: 0,
@@ -1636,7 +1641,7 @@ color: pink !important;`;
16361641
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
16371642

16381643
cssPropertyPrompt.setText('pin');
1639-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1644+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
16401645
text: 'color: pink;',
16411646
from: 3,
16421647
startTime: 0,
@@ -1662,7 +1667,7 @@ color: pink !important;`;
16621667

16631668
cssPropertyPrompt.setText('var(--rgb');
16641669
await cssPropertyPrompt.complete(true);
1665-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1670+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
16661671
text: 'color: var(--rgb-background-color);',
16671672
from: 0,
16681673
startTime: 0,
@@ -1681,7 +1686,7 @@ color: pink !important;`;
16811686
cssPropertyPrompt.attachAndStartEditing(attachedElement, noop);
16821687

16831688
cssPropertyPrompt.setText('p');
1684-
cssPropertyPrompt.aiCodeCompletionConfig?.setAiAutoCompletion?.({
1689+
cssPropertyPrompt.aiCodeCompletionProvider?.setAiAutoCompletion?.({
16851690
text: 'color: pink;',
16861691
from: 1,
16871692
startTime: 0,

front_end/panels/elements/StylesSidebarPane.ts

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
214214
#updateAbortController?: AbortController;
215215
#updateComputedStylesAbortController?: AbortController;
216216

217+
aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
218+
aiCodeCompletionProvider?: StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider;
219+
217220
constructor(computedStyleModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel) {
218221
super(computedStyleModel, {delegatesFocus: true});
219222
this.setMinimumSize(96, 26);
@@ -259,6 +262,22 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
259262
this.#scheduleResetUpdateIfNotEditing();
260263
}
261264
});
265+
266+
const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
267+
if (AiCodeCompletion.AiCodeCompletion.AiCodeCompletion.isAiCodeCompletionStylesEnabled(devtoolsLocale.locale)) {
268+
this.aiCodeCompletionConfig = {
269+
completionContext: {},
270+
generationContext: {},
271+
onFeatureEnabled: () => {},
272+
onFeatureDisabled: () => {},
273+
onSuggestionAccepted: () => {},
274+
onRequestTriggered: () => {},
275+
onResponseReceived: () => {},
276+
panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
277+
};
278+
this.aiCodeCompletionProvider =
279+
StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(this.aiCodeCompletionConfig);
280+
}
262281
}
263282

264283
get webCustomData(): WebCustomData|undefined {
@@ -1757,7 +1776,6 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
17571776
private treeElement: StylePropertyTreeElement;
17581777
private isEditingName: boolean;
17591778
private readonly cssVariables: string[];
1760-
aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
17611779
aiCodeCompletionProvider?: StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider;
17621780

17631781
#debouncedTriggerAiCodeCompletion = Common.Debouncer.debounce(() => {
@@ -1822,25 +1840,13 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
18221840
}
18231841
}
18241842

1825-
const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
1826-
if (AiCodeCompletion.AiCodeCompletion.AiCodeCompletion.isAiCodeCompletionStylesEnabled(devtoolsLocale.locale)) {
1827-
this.aiCodeCompletionConfig = {
1828-
completionContext: {},
1829-
generationContext: {},
1830-
onFeatureEnabled: () => {},
1831-
onFeatureDisabled: () => {},
1832-
onSuggestionAccepted: () => {},
1833-
onRequestTriggered: () => {},
1834-
onResponseReceived: () => {},
1835-
panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
1836-
getCompletionHint: this.getCompletionHint.bind(this),
1837-
getCurrentText: () => {
1838-
return this.text();
1839-
},
1840-
setAiAutoCompletion: this.setAiAutoCompletion.bind(this),
1841-
};
1842-
this.aiCodeCompletionProvider =
1843-
StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(this.aiCodeCompletionConfig);
1843+
const stylesContainer = this.treeElement.stylesContainer();
1844+
if (stylesContainer instanceof StylesSidebarPane) {
1845+
this.aiCodeCompletionProvider = stylesContainer.aiCodeCompletionProvider;
1846+
if (this.aiCodeCompletionProvider) {
1847+
this.aiCodeCompletionProvider.getCompletionHint = this.getCompletionHint.bind(this);
1848+
this.aiCodeCompletionProvider.setAiAutoCompletion = this.setAiAutoCompletion.bind(this);
1849+
}
18441850
}
18451851
}
18461852

front_end/ui/components/text_editor/AiCodeCompletionProvider.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,6 @@ export interface AiCodeCompletionConfig {
5656
onRequestTriggered: () => void;
5757
onResponseReceived: () => void;
5858
panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor;
59-
getCompletionHint?: () => string | null;
60-
getCurrentText?: () => string;
61-
setAiAutoCompletion?: (args: {
62-
text: string,
63-
from: number,
64-
startTime: number,
65-
onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
66-
clearCachedRequest: () => void,
67-
rpcGlobalId?: Host.AidaClient.RpcGlobalId,
68-
sampleId?: number,
69-
}|null) => void;
7059
}
7160

7261
export const DELAY_BEFORE_SHOWING_RESPONSE_MS = 500;

0 commit comments

Comments
 (0)