Skip to content

Commit

Permalink
Web Inspector: CSS source editor can adopt fuzzy search for code comp…
Browse files Browse the repository at this point in the history
…letion

rdar://125030691
https://bugs.webkit.org/show_bug.cgi?id=271260

Reviewed by Devin Rousso.

Use CSSCompletions.executeQuery instead of CSSCompletions.startsWith
when language mode is CSS, since executeQuery uses fuzzy search.

Also add an setting item in the Settings tab's Experimental sub-tab to
optionally turn this feature off.

* Source/WebInspectorUI/UserInterface/Controllers/CodeMirrorCompletionController.js:
(WI.CodeMirrorCompletionController.prototype._generateCSSCompletions):
   - Optionally apply fuzzy search by using `executeQuery`.

(WI.CodeMirrorCompletionController.prototype.updateCompletions):
   - The argument `completions` could now also be an array of objects
     instead of always an array of strings (due to executeQuery
     returning an array of objects). Those objects also contain info on
     which characters match in the fuzzy search, so the suggestion box
     can bold the matching text. `this._completions` however does not
     need this extra info, so we extract only the texts from
     `completions` for that.

(WI.CodeMirrorCompletionController.prototype._applyCompletionHint):
(WI.CodeMirrorCompletionController.prototype._applyCompletionHint.update):
   - Fuzzy search can now match completions not necessarily starting
     with the same text as currentText. Only show the gray watermark
     text (hint marker in code) when it's actually a prefix match.

*	Source/WebInspectorUI/UserInterface/Models/Completions.js: Added.
* Source/WebInspectorUI/UserInterface/Models/CSSCompletions.js:
(WI.CSSCompletions.getCompletionText):
   - As the getCompletionText helper function doesn't have to work for
     only CSS suggestions, it better belongs to a class with a more
     generic name like Completion instead of CSSCompletion.
   - Leave a note to eventually migrate all other usages of the old
     CSSCompletion.getCompletionText to Completion.getCompletionText.

* Source/WebInspectorUI/UserInterface/Main.html:
* Source/WebInspectorUI/UserInterface/Test.html:
   - Include the new Completions.js source file.

* Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js:
* Source/WebInspectorUI/UserInterface/Base/Setting.js:
* Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js:
   - Add an experimental setting item for this feature change.

Canonical link: https://commits.webkit.org/279144@main
  • Loading branch information
the-chenergy authored and rcaliman-apple committed May 22, 2024
1 parent ac7aecf commit e058a9c
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1854,6 +1854,7 @@ localizedStrings["Update Image"] = "Update Image";
localizedStrings["Update Local Override"] = "Update Local Override";
localizedStrings["Usage: %s"] = "Usage: %s";
localizedStrings["Use default media styles"] = "Use default media styles";
localizedStrings["Use fuzzy matching for CSS code completion"] = "Use fuzzy matching for CSS code completion";
localizedStrings["Use mock capture devices"] = "Use mock capture devices";
localizedStrings["User Agent"] = "User Agent";
localizedStrings["User Agent Style Sheet"] = "User Agent Style Sheet";
Expand Down
1 change: 1 addition & 0 deletions Source/WebInspectorUI/UserInterface/Base/Setting.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ WI.settings = {
experimentalEnableNetworkEmulatedCondition: new WI.Setting("experimental-enable-network-emulated-condition", false),
experimentalGroupSourceMapErrors: new WI.Setting("experimental-group-source-map-errors", true),
experimentalLimitSourceCodeHighlighting: new WI.Setting("engineering-limit-source-code-highlighting", false),
experimentalUseFuzzyMatchingForCSSCodeCompletion: new WI.Setting("experimental-use-fuzzy-matching-for-css-code-completion", true),

// Protocol
protocolLogAsText: new WI.Setting("protocol-log-as-text", false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ WI.CodeMirrorCompletionController = class CodeMirrorCompletionController extends
return;
}

this._completions = completions;
this._completions = completions.map(WI.Completions.getCompletionText);

if (typeof implicitSuffix === "string")
this._implicitSuffix = implicitSuffix;
Expand All @@ -106,11 +106,11 @@ WI.CodeMirrorCompletionController = class CodeMirrorCompletionController extends
var bounds = new WI.Rect(firstCharCoords.left, firstCharCoords.top, lastCharCoords.right - firstCharCoords.left, firstCharCoords.bottom - firstCharCoords.top);

// Try to restore the previous selected index, otherwise just select the first.
var index = this._currentCompletion ? completions.indexOf(this._currentCompletion) : 0;
let index = this._currentCompletion ? this._completions.indexOf(this._currentCompletion) : 0;
if (index === -1)
index = 0;

if (this._forced || completions.length > 1 || completions[index] !== this._prefix) {
if (this._forced || this._completions.length > 1 || this._completions[index] !== this._prefix) {
// Update and show the suggestion list.
this._suggestionsView.update(completions, index);
this._suggestionsView.show(bounds);
Expand All @@ -125,7 +125,7 @@ WI.CodeMirrorCompletionController = class CodeMirrorCompletionController extends
return;
}

this._applyCompletionHint(completions[index]);
this._applyCompletionHint(this._completions[index]);

this._resolveUpdatePromise(WI.CodeMirrorCompletionController.UpdatePromise.CompletionsFound);
}
Expand Down Expand Up @@ -305,7 +305,8 @@ WI.CodeMirrorCompletionController = class CodeMirrorCompletionController extends
var cursor = {line: this._lineNumber, ch: this._endOffset};
var currentText = this._codeMirror.getRange(from, cursor);

this._createCompletionHintMarker(cursor, replacementText.replace(currentText, ""));
if (replacementText.startsWith(currentText))
this._createCompletionHintMarker(cursor, replacementText.replace(currentText, ""));
}

this._ignoreChange = true;
Expand Down Expand Up @@ -584,12 +585,10 @@ WI.CodeMirrorCompletionController = class CodeMirrorCompletionController extends
if (!functionName)
return [];

let functionCompletions = WI.CSSKeywordCompletions.forFunction(functionName).startsWith(this._prefix);

if (this._delegate && this._delegate.completionControllerCSSFunctionValuesNeeded)
functionCompletions = this._delegate.completionControllerCSSFunctionValuesNeeded(this, functionName, functionCompletions);

return functionCompletions;
if (WI.settings.experimentalUseFuzzyMatchingForCSSCodeCompletion.value)
return WI.CSSKeywordCompletions.forFunction(functionName).executeQuery(this._prefix);
else
return WI.CSSKeywordCompletions.forFunction(functionName).startsWith(this._prefix);
}

// Scan backwards looking for the current property.
Expand Down Expand Up @@ -618,7 +617,11 @@ WI.CodeMirrorCompletionController = class CodeMirrorCompletionController extends
if (this._implicitSuffix === suffix)
this._implicitSuffix = "";

let completions = WI.CSSKeywordCompletions.forProperty(propertyName).startsWith(this._prefix);
let completions;
if (WI.settings.experimentalUseFuzzyMatchingForCSSCodeCompletion.value)
completions = WI.CSSKeywordCompletions.forProperty(propertyName).executeQuery(this._prefix);
else
completions = WI.CSSKeywordCompletions.forProperty(propertyName).startsWith(this._prefix);

if (suffix.startsWith("("))
completions = completions.map((x) => x.replace(/\(\)$/, ""));
Expand All @@ -629,6 +632,8 @@ WI.CodeMirrorCompletionController = class CodeMirrorCompletionController extends
this._implicitSuffix = suffix !== ":" ? ": " : "";

// Complete property names.
if (WI.settings.experimentalUseFuzzyMatchingForCSSCodeCompletion.value)
return WI.cssManager.propertyNameCompletions.executeQuery(this._prefix);
return WI.cssManager.propertyNameCompletions.startsWith(this._prefix);
}

Expand Down
1 change: 1 addition & 0 deletions Source/WebInspectorUI/UserInterface/Main.html
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@
<script src="Models/CollectionEntryPreview.js"></script>
<script src="Models/CollectionTypes.js"></script>
<script src="Models/Color.js"></script>
<script src="Models/Completions.js"></script>
<script src="Models/ConsoleCommandResultMessage.js"></script>
<script src="Models/ConsoleSnippet.js"></script>
<script src="Models/Cookie.js"></script>
Expand Down
11 changes: 2 additions & 9 deletions Source/WebInspectorUI/UserInterface/Models/CSSCompletions.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,8 @@ WI.CSSCompletions = class CSSCompletions

static getCompletionText(completion)
{
console.assert(typeof completion === "string" || completion instanceof WI.QueryResult, completion);

if (typeof completion === "string")
return completion;

if (completion instanceof WI.QueryResult)
return completion.value;

return "";
// FIXME <https://webkit.org/b/273721>: Make callers use the more generic WI.Completions.getCompletionText instead.
return WI.Completions.getCompletionText(completion);
}

// Public
Expand Down
41 changes: 41 additions & 0 deletions Source/WebInspectorUI/UserInterface/Models/Completions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

WI.Completions = class Completions
{
// Static

static getCompletionText(completion)
{
if (typeof completion === "string")
return completion;

if (completion instanceof WI.QueryResult)
return completion.value;

console.assert(false, "completion should be either String or WI.QueryResult; got", completion);
return "";
}
};
1 change: 1 addition & 0 deletions Source/WebInspectorUI/UserInterface/Test.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
<script src="Models/CollectionEntryPreview.js"></script>
<script src="Models/CollectionTypes.js"></script>
<script src="Models/Color.js"></script>
<script src="Models/Completions.js"></script>
<script src="Models/ConsoleCommandResultMessage.js"></script>
<script src="Models/ConsoleSnippet.js"></script>
<script src="Models/Cookie.js"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ WI.SettingsTabContentView = class SettingsTabContentView extends WI.TabContentVi

let sourcesGroup = experimentalSettingsView.addGroup(WI.UIString("Sources:"));
sourcesGroup.addSetting(WI.settings.experimentalLimitSourceCodeHighlighting, WI.UIString("Limit syntax highlighting on long lines of code"));
sourcesGroup.addSetting(WI.settings.experimentalUseFuzzyMatchingForCSSCodeCompletion, WI.UIString("Use fuzzy matching for CSS code completion"));

experimentalSettingsView.addSeparator();

Expand Down

0 comments on commit e058a9c

Please sign in to comment.