or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

code-completion.mdevent-streaming.mdfile-system.mdhttp-client.mdindex.mdnetwork-utilities.mdpackage-management.mdsvelte-integration.mdworker-management.md
tile.json

code-completion.mddocs/

Code Completion

Python code completion functionality using Jedi for development environments. Provides intelligent code suggestions, parameter hints, and documentation for Python code running in the WebAssembly worker.

Capabilities

Code Completion Request

Get code completion suggestions for Python code at a specific cursor position.

/**
 * Get code completions for Python code
 * @param request - Code completion request with code, line, and column
 * @returns Promise that resolves with completion suggestions
 */
getCodeCompletions(request: CodeCompletionRequest): Promise<CodeCompletionResponse>;

/**
 * Code completion request structure
 */
interface CodeCompletionRequest {
  /** Python code to analyze */
  code: string;
  /** Line number (0-based) where completion is requested */
  line: number;
  /** Column number (0-based) where completion is requested */
  column: number;
}

/**
 * Individual code completion suggestion
 */
interface CodeCompletion {
  /** Display label for the completion */
  label: string;
  /** Type of completion (function, class, variable, etc.) */
  type: string;
  /** Documentation string for the completion */
  docstring: string;
  /** Number of characters to replace from cursor position */
  completion_prefix_length: number;
}

/**
 * Array of completion suggestions
 */
type CodeCompletionResponse = CodeCompletion[];

Usage Examples:

import { WorkerProxy } from "@gradio/wasm";

const worker = new WorkerProxy({
  gradioWheelUrl: "https://example.com/gradio.whl",
  gradioClientWheelUrl: "https://example.com/gradio_client.whl",
  files: {},
  requirements: ["numpy", "pandas", "matplotlib"],
  sharedWorkerMode: false
});

worker.addEventListener("initialization-completed", async () => {
  // Basic code completion
  const completions = await worker.getCodeCompletions({
    code: "import numpy as np\nnp.",
    line: 1,
    column: 3
  });

  console.log("NumPy completions:");
  completions.forEach(completion => {
    console.log(`  ${completion.label} (${completion.type})`);
    if (completion.docstring) {
      console.log(`    ${completion.docstring.split('\n')[0]}`);
    }
  });

  // Method completion
  const methodCompletions = await worker.getCodeCompletions({
    code: `
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
df.`,
    line: 2,
    column: 3
  });

  console.log("DataFrame method completions:");
  methodCompletions.slice(0, 10).forEach(completion => {
    console.log(`  ${completion.label} (${completion.type})`);
  });

  // Variable completion in context
  const contextCompletions = await worker.getCodeCompletions({
    code: `
def process_data(data_frame, column_name):
    result = data_frame[column_name].mean()
    data_`,
    line: 2,
    column: 9
  });

  console.log("Context-aware completions:");
  contextCompletions.forEach(completion => {
    console.log(`  ${completion.label} (${completion.type})`);
  });
});

Interactive Code Editor Integration

Example integration with a code editor for real-time completions:

import { WorkerProxy } from "@gradio/wasm";

class PythonCodeEditor {
  private worker: WorkerProxy;
  private editorElement: HTMLTextAreaElement;
  private completionsList: HTMLDivElement;
  private currentCompletions: CodeCompletion[] = [];

  constructor(editorElement: HTMLTextAreaElement, worker: WorkerProxy) {
    this.worker = worker;
    this.editorElement = editorElement;
    this.setupEditor();
    this.createCompletionsUI();
  }

  private setupEditor() {
    // Set up event listeners for code completion
    this.editorElement.addEventListener('input', () => {
      this.debounceCompletion();
    });

    this.editorElement.addEventListener('keydown', (event) => {
      this.handleKeyDown(event);
    });

    // Position cursor tracking
    this.editorElement.addEventListener('click', () => {
      this.hideCompletions();
    });
  }

  private createCompletionsUI() {
    this.completionsList = document.createElement('div');
    this.completionsList.className = 'completions-list';
    this.completionsList.style.cssText = `
      position: absolute;
      background: white;
      border: 1px solid #ccc;
      border-radius: 4px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
      max-height: 200px;
      overflow-y: auto;
      z-index: 1000;
      display: none;
    `;
    document.body.appendChild(this.completionsList);
  }

  private debounceCompletion = this.debounce(async () => {
    await this.triggerCompletion();
  }, 300);

  private debounce(func: Function, wait: number) {
    let timeout: NodeJS.Timeout;
    return function executedFunction(...args: any[]) {
      const later = () => {
        clearTimeout(timeout);
        func(...args);
      };
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  private async triggerCompletion() {
    const cursorPosition = this.getCursorPosition();
    const code = this.editorElement.value;

    try {
      const completions = await this.worker.getCodeCompletions({
        code: code,
        line: cursorPosition.line,
        column: cursorPosition.column
      });

      if (completions.length > 0) {
        this.showCompletions(completions, cursorPosition);
      } else {
        this.hideCompletions();
      }
    } catch (error) {
      console.error("Code completion error:", error);
      this.hideCompletions();
    }
  }

  private getCursorPosition(): { line: number; column: number } {
    const textBeforeCursor = this.editorElement.value.substring(0, this.editorElement.selectionStart);
    const lines = textBeforeCursor.split('\n');
    
    return {
      line: lines.length - 1,
      column: lines[lines.length - 1].length
    };
  }

  private showCompletions(completions: CodeCompletion[], cursorPosition: { line: number; column: number }) {
    this.currentCompletions = completions;
    
    // Clear previous completions
    this.completionsList.innerHTML = '';

    // Add completion items
    completions.slice(0, 10).forEach((completion, index) => {
      const item = document.createElement('div');
      item.className = 'completion-item';
      item.style.cssText = `
        padding: 8px 12px;
        cursor: pointer;
        border-bottom: 1px solid #eee;
        font-family: monospace;
      `;

      const typeColor = this.getCompletionTypeColor(completion.type);
      item.innerHTML = `
        <div style="display: flex; justify-content: space-between; align-items: center;">
          <span style="font-weight: bold;">${completion.label}</span>
          <span style="font-size: 0.8em; color: ${typeColor};">${completion.type}</span>
        </div>
        ${completion.docstring ? `<div style="font-size: 0.8em; color: #666; margin-top: 4px;">${completion.docstring.split('\n')[0]}</div>` : ''}
      `;

      item.addEventListener('click', () => {
        this.insertCompletion(completion);
      });

      item.addEventListener('mouseenter', () => {
        item.style.backgroundColor = '#f0f0f0';
      });

      item.addEventListener('mouseleave', () => {
        item.style.backgroundColor = 'white';
      });

      this.completionsList.appendChild(item);
    });

    // Position the completions list
    this.positionCompletionsList();
    this.completionsList.style.display = 'block';
  }

  private getCompletionTypeColor(type: string): string {
    const colors = {
      'function': '#0066cc',
      'method': '#0066cc',
      'class': '#cc6600',
      'variable': '#009900',
      'module': '#990099',
      'keyword': '#cc0000'
    };
    return colors[type] || '#666666';
  }

  private positionCompletionsList() {
    const editorRect = this.editorElement.getBoundingClientRect();
    const cursorPosition = this.getCursorPosition();
    
    // Approximate cursor position (this would need more sophisticated calculation in practice)
    const lineHeight = 20;
    const charWidth = 8;
    
    this.completionsList.style.left = `${editorRect.left + cursorPosition.column * charWidth}px`;
    this.completionsList.style.top = `${editorRect.top + (cursorPosition.line + 1) * lineHeight}px`;
  }

  private insertCompletion(completion: CodeCompletion) {
    const cursorPos = this.editorElement.selectionStart;
    const textBefore = this.editorElement.value.substring(0, cursorPos - completion.completion_prefix_length);
    const textAfter = this.editorElement.value.substring(cursorPos);
    
    this.editorElement.value = textBefore + completion.label + textAfter;
    this.editorElement.selectionStart = this.editorElement.selectionEnd = textBefore.length + completion.label.length;
    
    this.hideCompletions();
    this.editorElement.focus();
  }

  private handleKeyDown(event: KeyboardEvent) {
    if (this.completionsList.style.display === 'block') {
      switch (event.key) {
        case 'Escape':
          event.preventDefault();
          this.hideCompletions();
          break;
        case 'Tab':
        case 'Enter':
          event.preventDefault();
          if (this.currentCompletions.length > 0) {
            this.insertCompletion(this.currentCompletions[0]);
          }
          break;
      }
    }
  }

  private hideCompletions() {
    this.completionsList.style.display = 'none';
    this.currentCompletions = [];
  }
}

// Usage
const editorElement = document.getElementById('python-editor') as HTMLTextAreaElement;
const codeEditor = new PythonCodeEditor(editorElement, worker);

Advanced Code Completion Features

Enhanced completion features for complex scenarios:

import { WorkerProxy } from "@gradio/wasm";

class AdvancedCodeCompletion {
  private worker: WorkerProxy;
  private completionCache: Map<string, { completions: CodeCompletion[]; timestamp: number }> = new Map();
  private cacheTimeout = 60000; // 1 minute cache

  constructor(worker: WorkerProxy) {
    this.worker = worker;
  }

  async getContextualCompletions(
    code: string, 
    line: number, 
    column: number,
    options: {
      includePrivate?: boolean;
      includeBuiltins?: boolean;
      maxCompletions?: number;
      prioritizeByType?: string[];
    } = {}
  ): Promise<CodeCompletion[]> {
    
    const cacheKey = `${code.substring(0, 1000)}:${line}:${column}`;
    const cached = this.completionCache.get(cacheKey);
    
    if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
      console.log("Using cached completions");
      return this.filterAndSortCompletions(cached.completions, options);
    }

    try {
      const completions = await this.worker.getCodeCompletions({
        code,
        line,
        column
      });

      // Cache the results
      this.completionCache.set(cacheKey, {
        completions,
        timestamp: Date.now()
      });

      return this.filterAndSortCompletions(completions, options);
    } catch (error) {
      console.error("Code completion failed:", error);
      return [];
    }
  }

  private filterAndSortCompletions(
    completions: CodeCompletion[], 
    options: {
      includePrivate?: boolean;
      includeBuiltins?: boolean;
      maxCompletions?: number;
      prioritizeByType?: string[];
    }
  ): CodeCompletion[] {
    
    let filtered = completions;

    // Filter private members
    if (!options.includePrivate) {
      filtered = filtered.filter(comp => !comp.label.startsWith('_'));
    }

    // Filter builtins
    if (!options.includeBuiltins) {
      filtered = filtered.filter(comp => comp.type !== 'builtin');
    }

    // Sort by priority types
    if (options.prioritizeByType && options.prioritizeByType.length > 0) {
      filtered.sort((a, b) => {
        const aPriority = options.prioritizeByType!.indexOf(a.type);
        const bPriority = options.prioritizeByType!.indexOf(b.type);
        
        if (aPriority !== -1 && bPriority !== -1) {
          return aPriority - bPriority;
        } else if (aPriority !== -1) {
          return -1;
        } else if (bPriority !== -1) {
          return 1;
        } else {
          return a.label.localeCompare(b.label);
        }
      });
    } else {
      // Default sorting by label
      filtered.sort((a, b) => a.label.localeCompare(b.label));
    }

    // Limit results
    if (options.maxCompletions && options.maxCompletions > 0) {
      filtered = filtered.slice(0, options.maxCompletions);
    }

    return filtered;
  }

  async getSignatureHelp(code: string, line: number, column: number): Promise<{
    signatures: Array<{
      label: string;
      documentation: string;
      parameters: Array<{
        label: string;
        documentation: string;
      }>;
    }>;
    activeSignature: number;
    activeParameter: number;
  } | null> {
    
    // This would require additional implementation in the worker
    // For now, we'll simulate signature help using completions
    try {
      await this.worker.runPythonCode(`
# Enhanced code analysis for signature help
import ast
import inspect
import sys

code_to_analyze = '''${code.replace(/'/g, "\\'")}'''
target_line = ${line}
target_column = ${column}

# This would need sophisticated AST analysis
# For now, we'll return a placeholder
print("SIGNATURE_HELP: Not implemented")
`);

      return null; // Placeholder
    } catch (error) {
      console.error("Signature help failed:", error);
      return null;
    }
  }

  async getHoverInformation(code: string, line: number, column: number): Promise<{
    content: string;
    range: { start: { line: number; column: number }; end: { line: number; column: number } };
  } | null> {
    
    try {
      // Get completions at the current position
      const completions = await this.worker.getCodeCompletions({
        code,
        line,
        column
      });

      // Find the most relevant completion
      const currentWord = this.getCurrentWord(code, line, column);
      const matchingCompletion = completions.find(comp => 
        comp.label === currentWord || comp.label.startsWith(currentWord)
      );

      if (matchingCompletion && matchingCompletion.docstring) {
        return {
          content: `**${matchingCompletion.label}** (${matchingCompletion.type})\n\n${matchingCompletion.docstring}`,
          range: {
            start: { line, column: column - currentWord.length },
            end: { line, column }
          }
        };
      }

      return null;
    } catch (error) {
      console.error("Hover information failed:", error);
      return null;
    }
  }

  private getCurrentWord(code: string, line: number, column: number): string {
    const lines = code.split('\n');
    if (line >= lines.length) return '';
    
    const currentLine = lines[line];
    const beforeCursor = currentLine.substring(0, column);
    const afterCursor = currentLine.substring(column);
    
    // Find word boundaries
    const wordBefore = beforeCursor.match(/[a-zA-Z_][a-zA-Z0-9_]*$/);
    const wordAfter = afterCursor.match(/^[a-zA-Z0-9_]*/);
    
    return (wordBefore ? wordBefore[0] : '') + (wordAfter ? wordAfter[0] : '');
  }

  clearCache(): void {
    this.completionCache.clear();
  }

  getCacheStats(): { size: number; entries: string[] } {
    return {
      size: this.completionCache.size,
      entries: Array.from(this.completionCache.keys())
    };
  }
}

// Usage
const advancedCompletion = new AdvancedCodeCompletion(worker);

// Get filtered completions
const completions = await advancedCompletion.getContextualCompletions(
  "import pandas as pd\ndf = pd.DataFrame()\ndf.",
  2,
  3,
  {
    includePrivate: false,
    maxCompletions: 20,
    prioritizeByType: ['method', 'function', 'property']
  }
);

// Get hover information
const hoverInfo = await advancedCompletion.getHoverInformation(
  "import numpy as np\nnp.array",
  1,
  8
);

if (hoverInfo) {
  console.log("Hover info:", hoverInfo.content);
}