or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

abbreviation-extraction.mdconfiguration.mdcore-expansion.mdindex.mdmarkup-processing.mdstylesheet-processing.md
tile.json

abbreviation-extraction.mddocs/

Abbreviation Extraction

Intelligent extraction of Emmet abbreviations from source code at specified positions, with support for prefix matching and auto-completion scenarios.

Capabilities

Extract Function

Extracts Emmet abbreviation from a line of text at a specified position, searching backward from the position to find abbreviation boundaries.

/**
 * Extracts Emmet abbreviation from given string
 * @param line - Text line where abbreviation should be extracted
 * @param pos - Caret position in line (defaults to end of line)
 * @param options - Extraction configuration options
 * @returns Extracted abbreviation data or undefined if no abbreviation found
 */
function extract(
  line: string, 
  pos?: number, 
  options?: Partial<ExtractOptions>
): ExtractedAbbreviation | undefined;

interface ExtractOptions {
  /** Look ahead for auto-closed characters like quotes and brackets */
  lookAhead: boolean;
  /** Type of syntax context ('markup' or 'stylesheet') */
  type: SyntaxType;
  /** Required prefix that must precede the abbreviation */
  prefix: string;
}

interface ExtractedAbbreviation {
  /** The extracted abbreviation string */
  abbreviation: string;
  /** Character position where abbreviation starts */
  location: number;
  /** Start position including any prefix */
  start: number;
  /** End position of the abbreviation */
  end: number;
}

Basic Usage Examples:

import { extract } from "emmet";

// Extract from end of line
const result1 = extract("Hello world ul.tabs>li");
console.log(result1);
// { abbreviation: "ul.tabs>li", location: 12, start: 12, end: 23 }

// Extract from specific position
const result2 = extract("div.container ul>li", 15);
console.log(result2);
// { abbreviation: "ul>li", location: 14, start: 14, end: 19 }

// No abbreviation found
const result3 = extract("Just plain text here");
console.log(result3); // undefined

Advanced Extraction Options

Look Ahead Option

Handles auto-inserted closing characters that editors commonly add when typing.

interface ExtractOptions {
  /**
   * Allow parser to look ahead of position for missing abbreviation parts.
   * Enabled by default to handle auto-inserted closing braces, quotes, etc.
   */
  lookAhead: boolean;
}

Look Ahead Examples:

import { extract } from "emmet";

const source = 'ul>li[title="Foo"]'; // Cursor after "Foo", before closing quote
const pos = 15; // Position after "Foo"

// With lookAhead enabled (default)
const result1 = extract(source, pos);
console.log(result1);
// { abbreviation: 'ul>li[title="Foo"]', location: 0, start: 0, end: 17 }

// With lookAhead disabled
const result2 = extract(source, pos, { lookAhead: false });
console.log(result2);
// { abbreviation: 'Foo', location: 12, start: 12, end: 15 }

Syntax Type Option

Determines how to interpret bracket characters based on markup vs stylesheet context.

interface ExtractOptions {
  /** 
   * Type of context syntax of expanded abbreviation.
   * In 'stylesheet' syntax, brackets [] and {} are not supported
   */
  type: SyntaxType;
}

type SyntaxType = 'markup' | 'stylesheet';

Syntax Type Examples:

import { extract } from "emmet";

const source = 'a{b}';
const pos = 3; // After "b"

// Markup context (default) - includes braces as text content
const markupResult = extract(source, pos, { type: 'markup' });
console.log(markupResult);
// { abbreviation: 'a{b}', location: 0, start: 0, end: 4 }

// Stylesheet context - braces not part of abbreviation syntax
const cssResult = extract(source, pos, { type: 'stylesheet' });
console.log(cssResult);
// { abbreviation: 'b', location: 2, start: 2, end: 3 }

Prefix Option

Requires abbreviation to be preceded by a specific prefix string, useful for preventing false positives in JSX and similar contexts.

interface ExtractOptions {
  /**
   * String that should precede abbreviation for successful extraction.
   * Useful for avoiding conflicts with variable names in JSX/JS contexts.
   */
  prefix: string;
}

Prefix Examples:

import { extract } from "emmet";

const jsxSource1 = '() => div';        // Variable name, not abbreviation
const jsxSource2 = '() => <div';       // JSX tag, valid abbreviation

// Without prefix - finds 'div' in both cases
extract(jsxSource1, jsxSource1.length);
// { abbreviation: 'div', location: 6, start: 6, end: 9 }

extract(jsxSource2, jsxSource2.length);
// { abbreviation: 'div', location: 7, start: 7, end: 10 }

// With prefix - only finds 'div' when preceded by '<'
extract(jsxSource1, jsxSource1.length, { prefix: '<' });
// undefined (no match)

extract(jsxSource2, jsxSource2.length, { prefix: '<' });
// { abbreviation: 'div', location: 7, start: 6, end: 10 }

Integration with Expansion

The extract function is designed to work seamlessly with the main expand function for editor integration scenarios.

Complete Workflow Example:

import expand, { extract } from "emmet";

function expandAbbreviationAtCursor(sourceCode: string, cursorPos: number) {
  // Extract abbreviation at cursor position
  const extracted = extract(sourceCode, cursorPos, {
    lookAhead: true,
    type: 'markup',
    prefix: '' // No prefix required
  });
  
  if (!extracted) {
    return null; // No abbreviation found
  }
  
  // Expand the extracted abbreviation
  const expanded = expand(extracted.abbreviation);
  
  // Return replacement info
  return {
    expanded,
    start: extracted.start,
    end: extracted.end,
    original: extracted.abbreviation
  };
}

// Usage in editor context
const code = "const template = ul.nav>li*3";
const cursor = code.length; // At end of line

const result = expandAbbreviationAtCursor(code, cursor);
if (result) {
  console.log(`Replace "${result.original}" with:`);
  console.log(result.expanded);
  // Replace "ul.nav>li*3" with:
  // <ul class="nav"><li></li><li></li><li></li></ul>
}

Error Handling

The extract function returns undefined when no valid abbreviation is found rather than throwing errors.

import { extract } from "emmet";

// Various cases that return undefined
console.log(extract(""));                    // Empty string
console.log(extract("just text"));          // No abbreviation pattern
console.log(extract("div", 0, { prefix: "<" })); // Prefix not found
console.log(extract("a{", 2));              // Incomplete abbreviation

// Always check for undefined before using result
const source = "Some code here";
const result = extract(source, source.length);

if (result) {
  console.log(`Found: ${result.abbreviation}`);
} else {
  console.log("No abbreviation found");
}