Skip to content

Commit

Permalink
fix(autocomplete): disable autocomplete for attributify props when no…
Browse files Browse the repository at this point in the history
…t using (#3685)

Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
Simon-He95 and antfu committed Apr 5, 2024
1 parent c37ce86 commit 4dfc319
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 17 deletions.
10 changes: 8 additions & 2 deletions packages/autocomplete/src/create.ts
Expand Up @@ -99,7 +99,7 @@ export function createAutocomplete(uno: UnoGenerator, options: AutocompleteOptio
return result
}

async function suggestInFile(content: string, cursor: number): Promise<SuggestResult> {
async function suggestInFile(content: string, cursor: number): Promise<SuggestResult | undefined> {
const isInsideAttrValue = searchAttrKey(content, cursor) !== undefined

// try resolve by extractors
Expand All @@ -114,7 +114,13 @@ export function createAutocomplete(uno: UnoGenerator, options: AutocompleteOptio
}

// regular resolve
const regular = searchUsageBoundary(content, cursor)
const regular = searchUsageBoundary(
content,
cursor,
(uno.config.presets || []).some(i => i.name === '@unocss/preset-attributify'),
)
if (!regular)
return
const suggestions = await suggest(regular.content, isInsideAttrValue)

return {
Expand Down
2 changes: 1 addition & 1 deletion packages/autocomplete/src/types.ts
Expand Up @@ -31,7 +31,7 @@ export interface ParsedAutocompleteTemplate {

export interface UnocssAutocomplete {
suggest: (input: string, allowsEmptyInput?: boolean) => Promise<string[]>
suggestInFile: (content: string, cursor: number) => Promise<SuggestResult>
suggestInFile: (content: string, cursor: number) => Promise<SuggestResult | undefined>
templates: (string | AutoCompleteFunction)[]
cache: LRUCache<string, string[]>
reset: () => void
Expand Down
46 changes: 41 additions & 5 deletions packages/autocomplete/src/utils.ts
@@ -1,15 +1,51 @@
export function searchUsageBoundary(line: string, index: number) {
export function searchUsageBoundary(
line: string,
index: number,
attributify = true,
) {
let start = index
let end = index

const regex = /[^\s>"'`;]/
while (start && regex.test(line.charAt(start - 1))) --start
while (end < line.length && regex.test(line.charAt(end))) ++end

return {
content: line.slice(start, end),
start,
end,
if (attributify) {
return {
content: line.slice(start, end),
start,
end,
}
}

let temp = start - 1
// match class="" or className=""
const matchClassText = 'class'
const matchClassNameText = 'className'
while (temp > matchClassText.length && !/[="{}><]/.test(line[temp--])) {
// Continue to match attrName forward
}
if (line[temp] !== '=')
return
if (temp > matchClassNameText.length) {
const data = line.slice(temp - matchClassNameText.length, temp)
if (data === matchClassNameText) {
return {
content: line.slice(start, end),
start,
end,
}
}
}
if (temp > matchClassText.length) {
const data = line.slice(temp - matchClassText.length, temp)
if (data === matchClassText) {
return {
content: line.slice(start, end),
start,
end,
}
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions packages/vscode/src/autocomplete.ts
Expand Up @@ -121,6 +121,9 @@ export async function registerAutoComplete(

const result = await autoComplete.suggestInFile(code, doc.offsetAt(position))

if (!result)
return

// log.appendLine(`🤖 ${id} | ${result.suggestions.slice(0, 10).map(v => `[${v[0]}, ${v[1]}]`).join(', ')}`)

if (!result.suggestions.length)
Expand Down
14 changes: 9 additions & 5 deletions test/autocomplete-utils.test.ts
Expand Up @@ -3,19 +3,23 @@ import { searchUsageBoundary } from '@unocss/autocomplete'

describe('searchUsageBoundary', () => {
it('works', () => {
expect(searchUsageBoundary('', 0).content)
expect(searchUsageBoundary('', 0)?.content)
.toMatchInlineSnapshot('""')

expect(searchUsageBoundary('<div class="p-1 p-2', 14).content)
expect(searchUsageBoundary('<div class="p-1 p-2', 14)?.content)
.toMatchInlineSnapshot('"p-1"')

expect(searchUsageBoundary('<div :class="`p-1 p-2', 16).content)
expect(searchUsageBoundary('<div :class="`p-1 p-2', 16, true)?.content)
.toMatchInlineSnapshot('"p-1"')

expect(searchUsageBoundary('<div p-1 p-2>', 10).content)
expect(searchUsageBoundary('<div p-1 p-2>', 10)?.content)
.toMatchInlineSnapshot('"p-2"')

expect(searchUsageBoundary('.a{ @apply p-2; }', 14).content)
expect(searchUsageBoundary('.a{ @apply p-2; }', 14)?.content)
.toMatchInlineSnapshot('"p-2"')

// No attributify
expect(searchUsageBoundary('<div p-1 p-2>', 10, false)?.content)
.toBe(undefined)
})
})
8 changes: 4 additions & 4 deletions test/autocomplete.test.ts
Expand Up @@ -159,10 +159,10 @@ describe('autocomplete', () => {
it('should support extractors', async () => {
const res = await ac.suggestInFile(fixture, 40)

expect(res.suggestions.every(i => i[0].startsWith('border-'))).toBeTruthy()
expect(res.suggestions.some(i => i[1].startsWith('border-'))).toBeFalsy()
expect(res?.suggestions.every(i => i[0].startsWith('border-'))).toBeTruthy()
expect(res?.suggestions.some(i => i[1].startsWith('border-'))).toBeFalsy()

const replacement = res.resolveReplacement(res.suggestions[0][0])
const replacement = res?.resolveReplacement(res?.suggestions[0][0])
expect(replacement).toMatchInlineSnapshot(`
{
"end": 40,
Expand All @@ -171,7 +171,7 @@ describe('autocomplete', () => {
}
`)

expect(fixture.slice(0, replacement.start) + replacement.replacement + fixture.slice(replacement.end))
expect(fixture.slice(0, replacement?.start) + replacement?.replacement + fixture.slice(replacement?.end))
.toMatchInlineSnapshot(`
"
<div bg="blue-500">
Expand Down

0 comments on commit 4dfc319

Please sign in to comment.