Skip to content

Instantly share code, notes, and snippets.

@kirankunigiri
Created April 5, 2025 02:17
Show Gist options
  • Save kirankunigiri/43c1283a173fa5eee8dbc8cfebf06cf6 to your computer and use it in GitHub Desktop.
Save kirankunigiri/43c1283a173fa5eee8dbc8cfebf06cf6 to your computer and use it in GitHub Desktop.
UnoCSS config with autocomplete for cn() utility function
import {
defineConfig,
presetIcons,
presetTypography,
presetWind3,
transformerDirectives,
transformerVariantGroup,
} from 'unocss';
export default defineConfig({
presets: [
presetWind3(),
presetIcons(),
presetTypography(),
],
transformers: [
transformerDirectives({ applyVariable: ['--at-apply', '--uno-apply', '--uno'] }),
transformerVariantGroup(),
],
// Enables autocomplete for cn() utility
autocomplete: {
extractors: [
{
name: 'cn-autocomplete',
extract: ({ content, cursor }) => {
const cnFunctionRE = /cn\(((?:'[^']*'|"[^"]*"|\`[^`]*\`|[^)])*)\)/g;
const splitterRE = /[\s'"`;,)]+/;
let args: string | undefined;
let fnPos = 0;
let match;
while ((match = cnFunctionRE.exec(content)) !== null) {
const [full, argsContent] = match;
const currentPos = match.index + 3; // 3 is length of "cn("
if (cursor > currentPos && cursor <= currentPos + argsContent.length) {
fnPos = currentPos;
args = argsContent;
break;
}
}
if (!args) return null;
// Find the specific argument where the cursor is
let matchSplit = splitterRE.exec(args);
let currentPos = 0;
let value: string | undefined;
while (matchSplit) {
const [matched] = matchSplit;
if (cursor > fnPos + currentPos && cursor <= fnPos + currentPos + matchSplit.index) {
value = args.slice(currentPos, currentPos + matchSplit.index);
break;
}
currentPos += matchSplit.index + matched.length;
matchSplit = splitterRE.exec(args.slice(currentPos));
}
if (value === undefined) {
value = args.slice(currentPos);
}
// Clean up the value by removing quotes
value = value.replace(/['"``]/g, '').trim();
// Handle conditional classes (x && 'class')
if (value.includes('&&')) {
value = value.split('&&')[1].trim();
}
return {
extracted: value,
resolveReplacement(suggestion) {
return {
start: fnPos + currentPos,
end: fnPos + currentPos + value!.length,
replacement: suggestion,
};
},
};
},
},
],
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment