All files / src decorationProvider.ts

0% Statements 0/64
100% Branches 1/1
100% Functions 1/1
0% Lines 0/64

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101                                                                                                                                                                                                         
import type { CodeDetector } from './codeDetector'
import * as vscode from 'vscode'
import { shouldProcessFile } from './fileUtils'
 
export class DecorationProvider {
  private detector: CodeDetector
  private decorationType: vscode.TextEditorDecorationType
  private disposables: vscode.Disposable[] = []
 
  constructor(detector: CodeDetector) {
    this.detector = detector
 
    // 创建装饰类型:下划线样式
    this.decorationType = vscode.window.createTextEditorDecorationType({
      textDecoration: 'underline',
      color: '#569cd6', // VS Code 蓝色
      cursor: 'pointer',
    })
 
    // 监听文档变化
    this.disposables.push(
      vscode.window.onDidChangeActiveTextEditor(this.updateDecorations, this),
      vscode.workspace.onDidChangeTextDocument(this.onDocumentChange, this),
    )
 
    // 初始化当前编辑器的装饰
    this.updateDecorations()
  }
 
  private onDocumentChange(event: vscode.TextDocumentChangeEvent) {
    const activeEditor = vscode.window.activeTextEditor
    if (activeEditor && event.document === activeEditor.document) {
      // 延迟更新装饰,避免频繁更新
      setTimeout(() => this.updateDecorations(), 100)
    }
  }
 
  private updateDecorations(editor?: vscode.TextEditor) {
    const activeEditor = editor || vscode.window.activeTextEditor
    if (!activeEditor) {
      return
    }
 
    const document = activeEditor.document
 
    // 检查文件是否应该被处理(包括文件类型和include配置)
    if (!shouldProcessFile(document)) {
      return
    }
 
    // 检查是否启用了自动检测
    const config = vscode.workspace.getConfiguration('vscode-json-string-code-editor')
    const enableAutoDetection = config.get('enableAutoDetection', true)
    if (!enableAutoDetection) {
      // 如果禁用了自动检测,清除所有装饰
      activeEditor.setDecorations(this.decorationType, [])
      return
    }
 
    // 检测所有代码块
    const codeBlocks = this.detector.detectAllCodeBlocks(document)
 
    // 创建装饰选项
    const decorations: vscode.DecorationOptions[] = codeBlocks.map((block) => {
      const markdown = new vscode.MarkdownString()
      markdown.isTrusted = true
 
      // 添加标题
      markdown.appendMarkdown(`**${block.language} Code Detected**\n\n`)
 
      // 添加编辑链接
      const editCommand = `command:vscode-json-string-code-editor.editCodeAtRange?${encodeURIComponent(JSON.stringify([document.uri.toString(), block]))}`
      markdown.appendMarkdown(`[✏️ Edit in temporary editor](${editCommand})\n\n`)
 
      // 添加代码预览(限制行数)
      const codeLines = block.code.split('\n')
      const previewLines = codeLines.slice(0, 5)
      const hasMore = codeLines.length > 5
 
      markdown.appendCodeblock(previewLines.join('\n'), block.language.toLowerCase())
 
      if (hasMore) {
        markdown.appendMarkdown(`\n*... and ${codeLines.length - 5} more lines*`)
      }
 
      return {
        range: block.range,
        hoverMessage: markdown,
      }
    })
 
    // 应用装饰
    activeEditor.setDecorations(this.decorationType, decorations)
  }
 
  public dispose() {
    this.decorationType.dispose()
    this.disposables.forEach(d => d.dispose())
  }
}