Skip to content

Commit addf57d

Browse files
committed
Fix words inside JSX tags not being completed
1 parent 5e83ab6 commit addf57d

File tree

2 files changed

+40
-37
lines changed

2 files changed

+40
-37
lines changed

package/src/extensions/autocomplete/javascript/index.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @module autocomplete/javascript */
22

33
import { PrismEditor } from "../../../index.js"
4+
import { TokenName } from "../../../prism/types.js"
45
import { braces, space } from "../../../prism/utils/jsx-shared.js"
56
import { re } from "../../../prism/utils/shared.js"
67
import { getClosestToken } from "../../../utils/index.js"
@@ -207,9 +208,11 @@ const includedTypes = new Set([
207208
"property-access",
208209
"maybe-class-name",
209210
"generic-function",
211+
"expression",
210212
])
211213

212-
const identifierFilter = (type: string) => includedTypes.has(type)
214+
const identifierFilter = (value: string) => (type: TokenName, start: number) =>
215+
includedTypes.has(type) || (type == "tag" && value[start] == "<")
213216

214217
const identifierSearch = re(/<0>+/.source, identifierPattern, "g")
215218

@@ -225,7 +228,13 @@ const completeIdentifiers = (identifiers?: Iterable<string>): CompletionSource<J
225228
? {
226229
from: getFrom(context),
227230
options: Array.from(
228-
findWords(context, editor, identifierFilter, identifierSearch, identifiers),
231+
findWords(
232+
context,
233+
editor,
234+
identifierFilter(editor.value),
235+
identifierSearch,
236+
identifiers,
237+
),
229238
label => ({
230239
label,
231240
icon: "text",
@@ -239,17 +248,14 @@ const completeIdentifiers = (identifiers?: Iterable<string>): CompletionSource<J
239248
/**
240249
* Completion source that wraps {@link completeIdentifiers} and {@link completeScope} and
241250
* removes duplicated options.
242-
*
251+
*
243252
* This means you can provide completions for both the `window` and words in the document
244253
* without duplicated options.
245254
* @param scope Scope object you want to provide completions for. For example `window`.
246255
* @param identifiers LList of identifiers that should be completed even if they're not
247256
* found in the document.
248257
*/
249-
const jsCompletion = (
250-
scope: any,
251-
identifiers?: Iterable<string>,
252-
): CompletionSource<JSContext> => {
258+
const jsCompletion = (scope: any, identifiers?: Iterable<string>): CompletionSource<JSContext> => {
253259
const cache = new WeakMap<any, [Completion[], Set<string>]>()
254260
const scopeSource = _completeScope(cache, scope)
255261

@@ -263,7 +269,13 @@ const jsCompletion = (
263269
labels = scopeResult[1]
264270
} else completions = []
265271

266-
findWords(context, editor, identifierFilter, identifierSearch, identifiers).forEach(word => {
272+
findWords(
273+
context,
274+
editor,
275+
identifierFilter(editor.value),
276+
identifierSearch,
277+
identifiers,
278+
).forEach(word => {
267279
if (!labels?.has(word))
268280
completions.push({
269281
label: word,

package/src/extensions/autocomplete/utils.ts

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { PrismEditor } from "../../index.js"
22
import { Token } from "../../prism/core.js"
3-
import { TokenStream } from "../../prism/types.js"
3+
import { TokenName, TokenStream } from "../../prism/types.js"
44
import { updateNode } from "../../utils/local.js"
55
import { matchTemplate } from "../search/search.js"
66
import { map } from "./tooltip.js"
7-
import { Completion, CompletionContext, CompletionSource} from "./types.js"
7+
import { Completion, CompletionContext, CompletionSource } from "./types.js"
88

99
const optionsFromKeys = (obj: object, icon?: string): Completion[] =>
1010
Object.keys(obj).map(tag => ({ label: tag, icon }))
@@ -54,7 +54,7 @@ const completeFromList = (options: Completion[]): CompletionSource<{ path: strin
5454
* @param filter Function used to filter tokens you want to search in. Is called with the
5555
* type of the token and its starting position. If the filter returns true, the token
5656
* will be searched.
57-
* @param pattern Pattern used to search for words.
57+
* @param pattern Pattern used to search for words. Must have the `g` flag.
5858
* @param init Words that should be completed even if they're not found in the document.
5959
* @param tokensOnly If `true` only the text of tokens whose `content` is a string will
6060
* be searched. If `false`, any string inside the {@link TokenStream} can be searched.
@@ -63,7 +63,7 @@ const completeFromList = (options: Completion[]): CompletionSource<{ path: strin
6363
const findWords = (
6464
context: CompletionContext,
6565
editor: PrismEditor,
66-
filter: (type: string, start: number) => boolean,
66+
filter: (type: TokenName, start: number) => boolean,
6767
pattern: RegExp,
6868
init?: Iterable<string>,
6969
tokensOnly?: boolean,
@@ -74,37 +74,28 @@ const findWords = (
7474
const search = (tokens: TokenStream, pos: number, isCorrectLang: boolean) => {
7575
let i = 0
7676
let token: string | Token
77-
if (isCorrectLang) {
78-
for (; (token = tokens[i++]); ) {
79-
if (typeof token == "string") {
80-
if (!tokensOnly) match(token, pos)
81-
} else {
82-
const type = token.type
83-
const content = token.content
84-
if ((token.alias || type).slice(0, 9) != "language-" && filter(type, pos)) {
85-
if (Array.isArray(content)) {
86-
search(content, pos, true)
87-
} else match(content, pos)
88-
}
89-
}
90-
pos += token.length
91-
}
92-
} else {
93-
for (; (token = tokens[i++]); ) {
94-
if (typeof token != "string") {
95-
const type = token.type
96-
const content = token.content
97-
if (Array.isArray(content)) {
98-
const aliasType = token.alias || type
77+
78+
for (; (token = tokens[i++]); ) {
79+
if (typeof token == "string") {
80+
if (!tokensOnly && isCorrectLang) match(token, pos)
81+
} else {
82+
const type = token.type
83+
const content = token.content
84+
const aliasType = token.alias || type
85+
86+
if (Array.isArray(content)) {
87+
if (!isCorrectLang || filter(type, pos)) {
9988
search(
10089
content,
10190
pos,
102-
aliasType.slice(0, 9) == "language-" ? definition == map[aliasType.slice(9)] : false,
91+
aliasType.slice(0, 9) == "language-"
92+
? definition == map[aliasType.slice(9)]
93+
: isCorrectLang,
10394
)
10495
}
105-
}
106-
pos += token.length
96+
} else if (isCorrectLang && filter(type, pos)) match(content, pos)
10797
}
98+
pos += token.length
10899
}
109100
}
110101
const match = (token: string, pos: number) => {

0 commit comments

Comments
 (0)