Skip to content

Editor API

Editor APIは、テキストエディターとの包括的な相互作用機能を提供し、テキストの操作、選択の管理、装飾の適用、エディターの動作の制御を可能にします。

概要

Editor APIを使用すると、以下のことができます:

  • テキストドキュメントの読み取りと編集
  • カーソル位置と選択範囲の管理
  • テキスト装飾とハイライトの適用
  • エディターの表示設定の制御
  • エディターイベントの処理
  • カスタムエディター機能の実装
  • 複数エディターの管理
  • エディターレイアウトの制御

基本的な使用方法

テキスト操作

typescript
import { TraeAPI } from '@trae/api';

// アクティブエディターを取得
const editor = TraeAPI.window.activeTextEditor;

if (editor) {
  const document = editor.document;
  
  // ドキュメント情報を取得
  console.log('ファイル名:', document.fileName);
  console.log('言語ID:', document.languageId);
  console.log('行数:', document.lineCount);
  console.log('変更されているか:', document.isDirty);
  
  // テキストを編集
  await editor.edit(editBuilder => {
    // 行の末尾にテキストを挿入
    const lastLine = document.lineAt(document.lineCount - 1);
    editBuilder.insert(lastLine.range.end, '\n// 新しい行が追加されました');
    
    // 特定の位置にテキストを挿入
    const position = new TraeAPI.Position(0, 0);
    editBuilder.insert(position, '// ファイルの先頭にコメント\n');
    
    // テキストを置換
    const range = new TraeAPI.Range(1, 0, 1, 10);
    editBuilder.replace(range, '置換されたテキスト');
    
    // テキストを削除
    const deleteRange = new TraeAPI.Range(2, 0, 3, 0);
    editBuilder.delete(deleteRange);
  });
}

// 新しいドキュメントを作成
async function createNewDocument() {
  const document = await TraeAPI.workspace.openTextDocument({
    content: '// 新しいファイル\nconsole.log("Hello, World!");',
    language: 'javascript'
  });
  
  // エディターで開く
  const editor = await TraeAPI.window.showTextDocument(document);
  
  return editor;
}

// ファイルを開く
async function openFile(filePath: string) {
  const document = await TraeAPI.workspace.openTextDocument(filePath);
  const editor = await TraeAPI.window.showTextDocument(document);
  
  return editor;
}

選択とカーソル管理

typescript
class SelectionManager {
  private editor: TraeAPI.TextEditor;

  constructor(editor: TraeAPI.TextEditor) {
    this.editor = editor;
    this.setupSelectionListeners();
  }

  private setupSelectionListeners() {
    // 選択変更をリッスン
    TraeAPI.window.onDidChangeTextEditorSelection(event => {
      if (event.textEditor === this.editor) {
        console.log('選択が変更されました:', {
          selections: event.selections,
          kind: event.kind
        });
        
        this.handleSelectionChange(event.selections);
      }
    });
  }

  private handleSelectionChange(selections: TraeAPI.Selection[]) {
    for (const selection of selections) {
      console.log('選択範囲:', {
        start: selection.start,
        end: selection.end,
        isEmpty: selection.isEmpty,
        isSingleLine: selection.isSingleLine,
        isReversed: selection.isReversed
      });
    }
  }

  // カーソルを特定の位置に移動
  moveCursorTo(line: number, character: number): void {
    const position = new TraeAPI.Position(line, character);
    const selection = new TraeAPI.Selection(position, position);
    this.editor.selection = selection;
    
    // ビューポートをカーソル位置に移動
    this.editor.revealRange(selection, TraeAPI.TextEditorRevealType.InCenter);
  }

  // テキストを選択
  selectText(startLine: number, startChar: number, endLine: number, endChar: number): void {
    const start = new TraeAPI.Position(startLine, startChar);
    const end = new TraeAPI.Position(endLine, endChar);
    const selection = new TraeAPI.Selection(start, end);
    
    this.editor.selection = selection;
    this.editor.revealRange(selection, TraeAPI.TextEditorRevealType.InCenterIfOutsideViewport);
  }

  // 複数選択を設定
  setMultipleSelections(ranges: Array<{startLine: number, startChar: number, endLine: number, endChar: number}>): void {
    const selections = ranges.map(range => {
      const start = new TraeAPI.Position(range.startLine, range.startChar);
      const end = new TraeAPI.Position(range.endLine, range.endChar);
      return new TraeAPI.Selection(start, end);
    });
    
    this.editor.selections = selections;
  }

  // 行全体を選択
  selectLine(lineNumber: number): void {
    const line = this.editor.document.lineAt(lineNumber);
    const selection = new TraeAPI.Selection(line.range.start, line.range.end);
    this.editor.selection = selection;
  }

  // 単語を選択
  selectWordAt(position: TraeAPI.Position): void {
    const wordRange = this.editor.document.getWordRangeAtPosition(position);
    if (wordRange) {
      const selection = new TraeAPI.Selection(wordRange.start, wordRange.end);
      this.editor.selection = selection;
    }
  }

  // 選択されたテキストを取得
  getSelectedText(): string {
    const selection = this.editor.selection;
    return this.editor.document.getText(selection);
  }

  // すべての選択されたテキストを取得
  getAllSelectedText(): string[] {
    return this.editor.selections.map(selection => 
      this.editor.document.getText(selection)
    );
  }

  // 選択範囲を拡張
  expandSelection(direction: 'up' | 'down' | 'left' | 'right', amount: number = 1): void {
    const selection = this.editor.selection;
    let newEnd = selection.end;

    switch (direction) {
      case 'up':
        newEnd = newEnd.translate(-amount, 0);
        break;
      case 'down':
        newEnd = newEnd.translate(amount, 0);
        break;
      case 'left':
        newEnd = newEnd.translate(0, -amount);
        break;
      case 'right':
        newEnd = newEnd.translate(0, amount);
        break;
    }

    this.editor.selection = new TraeAPI.Selection(selection.start, newEnd);
  }

  // 現在の行を選択
  selectCurrentLine(): void {
    const position = this.editor.selection.active;
    this.selectLine(position.line);
  }

  // 段落を選択
  selectParagraph(): void {
    const position = this.editor.selection.active;
    const document = this.editor.document;
    
    // 段落の開始を見つける
    let startLine = position.line;
    while (startLine > 0 && document.lineAt(startLine - 1).text.trim() !== '') {
      startLine--;
    }
    
    // 段落の終了を見つける
    let endLine = position.line;
    while (endLine < document.lineCount - 1 && document.lineAt(endLine + 1).text.trim() !== '') {
      endLine++;
    }
    
    const start = new TraeAPI.Position(startLine, 0);
    const end = document.lineAt(endLine).range.end;
    this.editor.selection = new TraeAPI.Selection(start, end);
  }
}

// 選択マネージャーを初期化
const activeEditor = TraeAPI.window.activeTextEditor;
if (activeEditor) {
  const selectionManager = new SelectionManager(activeEditor);
}

テキスト装飾

typescript
class TextDecorationManager {
  private editor: TraeAPI.TextEditor;
  private decorationTypes: Map<string, TraeAPI.TextEditorDecorationType> = new Map();

  constructor(editor: TraeAPI.TextEditor) {
    this.editor = editor;
    this.initializeDecorationTypes();
  }

  private initializeDecorationTypes() {
    // エラーハイライト用の装飾タイプ
    const errorDecorationType = TraeAPI.window.createTextEditorDecorationType({
      backgroundColor: 'rgba(255, 0, 0, 0.1)',
      border: '1px solid red',
      borderRadius: '2px',
      overviewRulerColor: 'red',
      overviewRulerLane: TraeAPI.OverviewRulerLane.Right,
      light: {
        backgroundColor: 'rgba(255, 0, 0, 0.05)'
      },
      dark: {
        backgroundColor: 'rgba(255, 0, 0, 0.15)'
      }
    });
    this.decorationTypes.set('error', errorDecorationType);

    // 警告ハイライト用の装飾タイプ
    const warningDecorationType = TraeAPI.window.createTextEditorDecorationType({
      backgroundColor: 'rgba(255, 165, 0, 0.1)',
      border: '1px solid orange',
      borderRadius: '2px',
      overviewRulerColor: 'orange',
      overviewRulerLane: TraeAPI.OverviewRulerLane.Right
    });
    this.decorationTypes.set('warning', warningDecorationType);

    // 情報ハイライト用の装飾タイプ
    const infoDecorationType = TraeAPI.window.createTextEditorDecorationType({
      backgroundColor: 'rgba(0, 0, 255, 0.1)',
      border: '1px solid blue',
      borderRadius: '2px',
      overviewRulerColor: 'blue',
      overviewRulerLane: TraeAPI.OverviewRulerLane.Right
    });
    this.decorationTypes.set('info', infoDecorationType);

    // ハイライト用の装飾タイプ
    const highlightDecorationType = TraeAPI.window.createTextEditorDecorationType({
      backgroundColor: 'rgba(255, 255, 0, 0.3)',
      overviewRulerColor: 'yellow',
      overviewRulerLane: TraeAPI.OverviewRulerLane.Center
    });
    this.decorationTypes.set('highlight', highlightDecorationType);

    // 行番号装飾用の装飾タイプ
    const lineNumberDecorationType = TraeAPI.window.createTextEditorDecorationType({
      isWholeLine: true,
      backgroundColor: 'rgba(0, 255, 0, 0.1)',
      gutterIconPath: TraeAPI.Uri.file('/path/to/icon.svg'),
      gutterIconSize: 'contain'
    });
    this.decorationTypes.set('lineNumber', lineNumberDecorationType);

    // カスタムCSS装飾
    const customDecorationType = TraeAPI.window.createTextEditorDecorationType({
      before: {
        contentText: '→ ',
        color: 'gray',
        fontWeight: 'bold'
      },
      after: {
        contentText: ' ←',
        color: 'gray'
      },
      textDecoration: 'underline dotted'
    });
    this.decorationTypes.set('custom', customDecorationType);
  }

  // 装飾を適用
  applyDecoration(
    type: string, 
    ranges: TraeAPI.Range[], 
    options?: { hoverMessage?: string; renderOptions?: any }
  ): void {
    const decorationType = this.decorationTypes.get(type);
    if (!decorationType) {
      console.error(`装飾タイプ '${type}' が見つかりません`);
      return;
    }

    const decorationOptions: TraeAPI.DecorationOptions[] = ranges.map(range => ({
      range,
      hoverMessage: options?.hoverMessage,
      renderOptions: options?.renderOptions
    }));

    this.editor.setDecorations(decorationType, decorationOptions);
  }

  // エラーをハイライト
  highlightErrors(errors: Array<{ range: TraeAPI.Range; message: string }>): void {
    const decorationOptions: TraeAPI.DecorationOptions[] = errors.map(error => ({
      range: error.range,
      hoverMessage: `エラー: ${error.message}`
    }));

    const errorDecorationType = this.decorationTypes.get('error')!;
    this.editor.setDecorations(errorDecorationType, decorationOptions);
  }

  // 検索結果をハイライト
  highlightSearchResults(searchTerm: string): void {
    const document = this.editor.document;
    const text = document.getText();
    const ranges: TraeAPI.Range[] = [];
    
    let match;
    const regex = new RegExp(searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
    
    while ((match = regex.exec(text)) !== null) {
      const startPos = document.positionAt(match.index);
      const endPos = document.positionAt(match.index + match[0].length);
      ranges.push(new TraeAPI.Range(startPos, endPos));
    }

    this.applyDecoration('highlight', ranges, {
      hoverMessage: `検索結果: "${searchTerm}"`
    });
  }

  // 行をハイライト
  highlightLines(lineNumbers: number[], message?: string): void {
    const ranges = lineNumbers.map(lineNumber => {
      const line = this.editor.document.lineAt(lineNumber);
      return line.range;
    });

    this.applyDecoration('lineNumber', ranges, {
      hoverMessage: message || 'ハイライトされた行'
    });
  }

  // 単語をハイライト
  highlightWord(word: string): void {
    const document = this.editor.document;
    const ranges: TraeAPI.Range[] = [];
    
    for (let i = 0; i < document.lineCount; i++) {
      const line = document.lineAt(i);
      const text = line.text;
      
      let index = 0;
      while ((index = text.indexOf(word, index)) !== -1) {
        const start = new TraeAPI.Position(i, index);
        const end = new TraeAPI.Position(i, index + word.length);
        ranges.push(new TraeAPI.Range(start, end));
        index += word.length;
      }
    }

    this.applyDecoration('highlight', ranges, {
      hoverMessage: `単語: "${word}"`
    });
  }

  // すべての装飾をクリア
  clearAllDecorations(): void {
    for (const decorationType of this.decorationTypes.values()) {
      this.editor.setDecorations(decorationType, []);
    }
  }

  // 特定の装飾タイプをクリア
  clearDecoration(type: string): void {
    const decorationType = this.decorationTypes.get(type);
    if (decorationType) {
      this.editor.setDecorations(decorationType, []);
    }
  }

  // 装飾タイプを破棄
  dispose(): void {
    for (const decorationType of this.decorationTypes.values()) {
      decorationType.dispose();
    }
    this.decorationTypes.clear();
  }

  // カスタム装飾を作成
  createCustomDecoration(
    name: string,
    options: TraeAPI.DecorationRenderOptions
  ): void {
    const decorationType = TraeAPI.window.createTextEditorDecorationType(options);
    this.decorationTypes.set(name, decorationType);
  }

  // 動的装飾(アニメーション効果)
  animateDecoration(type: string, ranges: TraeAPI.Range[], duration: number = 1000): void {
    this.applyDecoration(type, ranges);
    
    setTimeout(() => {
      this.clearDecoration(type);
    }, duration);
  }
}

// テキスト装飾マネージャーを初期化
const activeEditor = TraeAPI.window.activeTextEditor;
if (activeEditor) {
  const decorationManager = new TextDecorationManager(activeEditor);
  
  // 使用例
  decorationManager.highlightSearchResults('function');
  decorationManager.highlightLines([0, 5, 10], 'ブックマークされた行');
}

エディター設定とビュー制御

typescript
class EditorViewController {
  private editor: TraeAPI.TextEditor;

  constructor(editor: TraeAPI.TextEditor) {
    this.editor = editor;
    this.setupViewListeners();
  }

  private setupViewListeners() {
    // ビューポート変更をリッスン
    TraeAPI.window.onDidChangeTextEditorVisibleRanges(event => {
      if (event.textEditor === this.editor) {
        console.log('表示範囲が変更されました:', event.visibleRanges);
      }
    });

    // エディターオプション変更をリッスン
    TraeAPI.window.onDidChangeTextEditorOptions(event => {
      if (event.textEditor === this.editor) {
        console.log('エディターオプションが変更されました:', event.options);
      }
    });

    // ビューカラム変更をリッスン
    TraeAPI.window.onDidChangeTextEditorViewColumn(event => {
      if (event.textEditor === this.editor) {
        console.log('ビューカラムが変更されました:', event.viewColumn);
      }
    });
  }

  // エディターオプションを設定
  setEditorOptions(options: Partial<TraeAPI.TextEditorOptions>): void {
    this.editor.options = {
      ...this.editor.options,
      ...options
    };
  }

  // タブサイズを設定
  setTabSize(size: number): void {
    this.setEditorOptions({ tabSize: size });
  }

  // インデントタイプを設定
  setIndentType(useSpaces: boolean): void {
    this.setEditorOptions({ insertSpaces: useSpaces });
  }

  // 行番号表示を切り替え
  toggleLineNumbers(): void {
    // 注意:これはエディター設定であり、ワークスペース設定を通じて制御されます
    const config = TraeAPI.workspace.getConfiguration('editor');
    const current = config.get<string>('lineNumbers', 'on');
    const newValue = current === 'on' ? 'off' : 'on';
    config.update('lineNumbers', newValue, TraeAPI.ConfigurationTarget.Workspace);
  }

  // 単語の折り返しを切り替え
  toggleWordWrap(): void {
    const config = TraeAPI.workspace.getConfiguration('editor');
    const current = config.get<string>('wordWrap', 'off');
    const newValue = current === 'off' ? 'on' : 'off';
    config.update('wordWrap', newValue, TraeAPI.ConfigurationTarget.Workspace);
  }

  // 特定の行にスクロール
  scrollToLine(lineNumber: number, position: 'top' | 'center' | 'bottom' = 'center'): void {
    const line = this.editor.document.lineAt(lineNumber);
    const revealType = position === 'top' ? TraeAPI.TextEditorRevealType.AtTop :
                      position === 'bottom' ? TraeAPI.TextEditorRevealType.Default :
                      TraeAPI.TextEditorRevealType.InCenter;
    
    this.editor.revealRange(line.range, revealType);
  }

  // 範囲を表示
  revealRange(range: TraeAPI.Range, revealType: TraeAPI.TextEditorRevealType = TraeAPI.TextEditorRevealType.Default): void {
    this.editor.revealRange(range, revealType);
  }

  // 表示範囲を取得
  getVisibleRanges(): TraeAPI.Range[] {
    return this.editor.visibleRanges;
  }

  // エディターが表示されているかチェック
  isVisible(): boolean {
    return this.editor.visibleRanges.length > 0;
  }

  // エディターのビューカラムを取得
  getViewColumn(): TraeAPI.ViewColumn | undefined {
    return this.editor.viewColumn;
  }

  // フォントサイズを変更
  changeFontSize(delta: number): void {
    const config = TraeAPI.workspace.getConfiguration('editor');
    const currentSize = config.get<number>('fontSize', 14);
    const newSize = Math.max(8, Math.min(72, currentSize + delta));
    config.update('fontSize', newSize, TraeAPI.ConfigurationTarget.Global);
  }

  // ズームレベルを設定
  setZoomLevel(level: number): void {
    const config = TraeAPI.workspace.getConfiguration('window');
    config.update('zoomLevel', level, TraeAPI.ConfigurationTarget.Global);
  }

  // ミニマップの表示を切り替え
  toggleMinimap(): void {
    const config = TraeAPI.workspace.getConfiguration('editor.minimap');
    const current = config.get<boolean>('enabled', true);
    config.update('enabled', !current, TraeAPI.ConfigurationTarget.Workspace);
  }

  // 空白文字の表示を切り替え
  toggleRenderWhitespace(): void {
    const config = TraeAPI.workspace.getConfiguration('editor');
    const current = config.get<string>('renderWhitespace', 'selection');
    const newValue = current === 'none' ? 'all' : 'none';
    config.update('renderWhitespace', newValue, TraeAPI.ConfigurationTarget.Workspace);
  }

  // インデントガイドの表示を切り替え
  toggleIndentGuides(): void {
    const config = TraeAPI.workspace.getConfiguration('editor');
    const current = config.get<boolean>('renderIndentGuides', true);
    config.update('renderIndentGuides', !current, TraeAPI.ConfigurationTarget.Workspace);
  }

  // エディターのテーマを変更
  changeTheme(themeId: string): void {
    const config = TraeAPI.workspace.getConfiguration('workbench');
    config.update('colorTheme', themeId, TraeAPI.ConfigurationTarget.Global);
  }

  // 分割ビューでエディターを開く
  async openInSplitView(viewColumn: TraeAPI.ViewColumn): Promise<TraeAPI.TextEditor> {
    return await TraeAPI.window.showTextDocument(this.editor.document, {
      viewColumn: viewColumn,
      preserveFocus: false,
      preview: false
    });
  }

  // エディターを閉じる
  async closeEditor(): Promise<void> {
    await TraeAPI.commands.executeCommand('workbench.action.closeActiveEditor');
  }

  // すべてのエディターを閉じる
  async closeAllEditors(): Promise<void> {
    await TraeAPI.commands.executeCommand('workbench.action.closeAllEditors');
  }

  // エディターグループを分割
  async splitEditor(direction: 'horizontal' | 'vertical' = 'vertical'): Promise<void> {
    const command = direction === 'horizontal' ? 
      'workbench.action.splitEditorDown' : 
      'workbench.action.splitEditor';
    await TraeAPI.commands.executeCommand(command);
  }
}

// エディタービューコントローラーを初期化
const activeEditor = TraeAPI.window.activeTextEditor;
if (activeEditor) {
  const viewController = new EditorViewController(activeEditor);
  
  // 使用例
  viewController.setTabSize(2);
  viewController.scrollToLine(50, 'center');
  viewController.changeFontSize(2);
}

エディターイベント処理

typescript
class EditorEventHandler {
  private disposables: TraeAPI.Disposable[] = [];

  constructor() {
    this.setupEventListeners();
  }

  private setupEventListeners() {
    // アクティブエディター変更
    this.disposables.push(
      TraeAPI.window.onDidChangeActiveTextEditor(editor => {
        if (editor) {
          console.log('アクティブエディターが変更されました:', editor.document.fileName);
          this.onActiveEditorChanged(editor);
        } else {
          console.log('アクティブエディターがありません');
        }
      })
    );

    // テキスト変更
    this.disposables.push(
      TraeAPI.workspace.onDidChangeTextDocument(event => {
        console.log('ドキュメントが変更されました:', {
          fileName: event.document.fileName,
          changes: event.contentChanges.length,
          reason: event.reason
        });
        
        this.onTextDocumentChanged(event);
      })
    );

    // ドキュメント保存
    this.disposables.push(
      TraeAPI.workspace.onDidSaveTextDocument(document => {
        console.log('ドキュメントが保存されました:', document.fileName);
        this.onDocumentSaved(document);
      })
    );

    // ドキュメントを開く
    this.disposables.push(
      TraeAPI.workspace.onDidOpenTextDocument(document => {
        console.log('ドキュメントが開かれました:', document.fileName);
        this.onDocumentOpened(document);
      })
    );

    // ドキュメントを閉じる
    this.disposables.push(
      TraeAPI.workspace.onDidCloseTextDocument(document => {
        console.log('ドキュメントが閉じられました:', document.fileName);
        this.onDocumentClosed(document);
      })
    );

    // カーソル位置変更
    this.disposables.push(
      TraeAPI.window.onDidChangeTextEditorSelection(event => {
        console.log('選択が変更されました:', {
          editor: event.textEditor.document.fileName,
          selections: event.selections.length,
          kind: event.kind
        });
        
        this.onSelectionChanged(event);
      })
    );
  }

  private onActiveEditorChanged(editor: TraeAPI.TextEditor): void {
    // アクティブエディター変更時の処理
    const document = editor.document;
    
    // 言語固有の処理
    switch (document.languageId) {
      case 'javascript':
      case 'typescript':
        this.setupJavaScriptFeatures(editor);
        break;
      case 'python':
        this.setupPythonFeatures(editor);
        break;
      case 'html':
        this.setupHTMLFeatures(editor);
        break;
    }
    
    // ファイルサイズチェック
    if (document.getText().length > 1000000) { // 1MB以上
      TraeAPI.window.showWarningMessage('大きなファイルです。パフォーマンスが低下する可能性があります。');
    }
  }

  private onTextDocumentChanged(event: TraeAPI.TextDocumentChangeEvent): void {
    const document = event.document;
    
    // 変更内容を分析
    for (const change of event.contentChanges) {
      console.log('変更詳細:', {
        range: change.range,
        text: change.text,
        rangeLength: change.rangeLength
      });
      
      // 特定のパターンを検出
      if (change.text.includes('TODO')) {
        this.highlightTODOs(document);
      }
      
      if (change.text.includes('console.log')) {
        this.highlightConsoleStatements(document);
      }
    }
    
    // 自動保存の実装
    if (document.isDirty && this.shouldAutoSave(document)) {
      this.autoSave(document);
    }
  }

  private onDocumentSaved(document: TraeAPI.TextDocument): void {
    // 保存後の処理
    console.log(`ファイル "${document.fileName}" が保存されました`);
    
    // 保存統計を更新
    this.updateSaveStatistics(document);
    
    // 自動フォーマット
    if (this.shouldAutoFormat(document)) {
      this.formatDocument(document);
    }
    
    // リンターを実行
    this.runLinter(document);
  }

  private onDocumentOpened(document: TraeAPI.TextDocument): void {
    // ドキュメントを開いた時の処理
    console.log(`ファイル "${document.fileName}" が開かれました`);
    
    // ファイル統計を更新
    this.updateFileStatistics(document);
    
    // 最近使用したファイルリストを更新
    this.updateRecentFiles(document);
  }

  private onDocumentClosed(document: TraeAPI.TextDocument): void {
    // ドキュメントを閉じた時の処理
    console.log(`ファイル "${document.fileName}" が閉じられました`);
    
    // 未保存の変更があるかチェック
    if (document.isDirty) {
      TraeAPI.window.showWarningMessage(
        `ファイル "${document.fileName}" に未保存の変更があります。`
      );
    }
    
    // リソースをクリーンアップ
    this.cleanupDocumentResources(document);
  }

  private onSelectionChanged(event: TraeAPI.TextEditorSelectionChangeEvent): void {
    const editor = event.textEditor;
    const selections = event.selections;
    
    // 選択されたテキストの統計
    const selectedText = selections.map(selection => 
      editor.document.getText(selection)
    ).join('\n');
    
    if (selectedText.length > 0) {
      console.log('選択されたテキスト統計:', {
        文字数: selectedText.length,
        行数: selectedText.split('\n').length,
        単語数: selectedText.split(/\s+/).filter(word => word.length > 0).length
      });
    }
    
    // 選択範囲に基づく機能
    if (selections.length === 1 && !selections[0].isEmpty) {
      this.highlightSimilarText(editor, selectedText);
    }
  }

  // ヘルパーメソッド
  private setupJavaScriptFeatures(editor: TraeAPI.TextEditor): void {
    // JavaScript固有の機能を設定
    console.log('JavaScript機能を設定中...');
  }

  private setupPythonFeatures(editor: TraeAPI.TextEditor): void {
    // Python固有の機能を設定
    console.log('Python機能を設定中...');
  }

  private setupHTMLFeatures(editor: TraeAPI.TextEditor): void {
    // HTML固有の機能を設定
    console.log('HTML機能を設定中...');
  }

  private highlightTODOs(document: TraeAPI.TextDocument): void {
    // TODOコメントをハイライト
    console.log('TODOコメントをハイライト中...');
  }

  private highlightConsoleStatements(document: TraeAPI.TextDocument): void {
    // console.logステートメントをハイライト
    console.log('console.logステートメントをハイライト中...');
  }

  private shouldAutoSave(document: TraeAPI.TextDocument): boolean {
    // 自動保存の条件をチェック
    const config = TraeAPI.workspace.getConfiguration('files');
    return config.get<string>('autoSave', 'off') !== 'off';
  }

  private async autoSave(document: TraeAPI.TextDocument): Promise<void> {
    try {
      await document.save();
      console.log('自動保存が完了しました');
    } catch (error) {
      console.error('自動保存に失敗しました:', error);
    }
  }

  private shouldAutoFormat(document: TraeAPI.TextDocument): boolean {
    const config = TraeAPI.workspace.getConfiguration('editor');
    return config.get<boolean>('formatOnSave', false);
  }

  private async formatDocument(document: TraeAPI.TextDocument): Promise<void> {
    try {
      await TraeAPI.commands.executeCommand('editor.action.formatDocument');
      console.log('ドキュメントのフォーマットが完了しました');
    } catch (error) {
      console.error('フォーマットに失敗しました:', error);
    }
  }

  private runLinter(document: TraeAPI.TextDocument): void {
    // リンターを実行
    console.log('リンターを実行中...');
  }

  private updateSaveStatistics(document: TraeAPI.TextDocument): void {
    // 保存統計を更新
    console.log('保存統計を更新中...');
  }

  private updateFileStatistics(document: TraeAPI.TextDocument): void {
    // ファイル統計を更新
    console.log('ファイル統計を更新中...');
  }

  private updateRecentFiles(document: TraeAPI.TextDocument): void {
    // 最近使用したファイルリストを更新
    console.log('最近使用したファイルリストを更新中...');
  }

  private cleanupDocumentResources(document: TraeAPI.TextDocument): void {
    // ドキュメントリソースをクリーンアップ
    console.log('ドキュメントリソースをクリーンアップ中...');
  }

  private highlightSimilarText(editor: TraeAPI.TextEditor, selectedText: string): void {
    // 類似テキストをハイライト
    console.log('類似テキストをハイライト中...');
  }

  // リソースを破棄
  dispose(): void {
    this.disposables.forEach(disposable => disposable.dispose());
    this.disposables = [];
  }
}

// エディターイベントハンドラーを初期化
const eventHandler = new EditorEventHandler();

APIリファレンス

コアインターフェース

typescript
interface TextEditor {
  readonly document: TextDocument;
  selection: Selection;
  selections: Selection[];
  readonly visibleRanges: Range[];
  options: TextEditorOptions;
  readonly viewColumn?: ViewColumn;
  
  edit(callback: (editBuilder: TextEditorEdit) => void): Thenable<boolean>;
  insertSnippet(snippet: SnippetString, location?: Position | Range | Position[] | Range[]): Thenable<boolean>;
  setDecorations(decorationType: TextEditorDecorationType, rangesOrOptions: Range[] | DecorationOptions[]): void;
  revealRange(range: Range, revealType?: TextEditorRevealType): void;
  show(column?: ViewColumn): void;
  hide(): void;
}

interface TextDocument {
  readonly uri: Uri;
  readonly fileName: string;
  readonly isUntitled: boolean;
  readonly languageId: string;
  readonly version: number;
  readonly isDirty: boolean;
  readonly isClosed: boolean;
  readonly lineCount: number;
  
  save(): Thenable<boolean>;
  getText(range?: Range): string;
  getWordRangeAtPosition(position: Position, regex?: RegExp): Range | undefined;
  lineAt(line: number): TextLine;
  positionAt(offset: number): Position;
  offsetAt(position: Position): number;
  validateRange(range: Range): Range;
  validatePosition(position: Position): Position;
}

interface TextEditorEdit {
  replace(location: Position | Range | Selection, value: string): void;
  insert(location: Position, value: string): void;
  delete(location: Range | Selection): void;
  setEndOfLine(endOfLine: EndOfLine): void;
}

interface Selection extends Range {
  readonly anchor: Position;
  readonly active: Position;
  readonly isReversed: boolean;
}

interface TextEditorDecorationType {
  readonly key: string;
  dispose(): void;
}

ベストプラクティス

  1. パフォーマンス: 大きなファイルでは遅延読み込みとバッチ処理を使用
  2. メモリ管理: 不要な装飾とイベントリスナーを適切に破棄
  3. ユーザーエクスペリエンス: 長時間の操作には進行状況を表示
  4. エラーハンドリング: ファイル操作の失敗を適切に処理
  5. 設定: ユーザー設定を尊重し、適切なデフォルト値を提供
  6. アクセシビリティ: スクリーンリーダーと互換性のある装飾を使用
  7. テスト: さまざまなファイルタイプとサイズでテスト
  8. ドキュメント: API使用方法の明確な例を提供

関連API

究極の AI 駆動 IDE 学習ガイド