You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React CodeMirror中实现高级Python自动补全?

解决方案:修复CodeMirror Python补全问题,实现点号方法提示

核心问题分析

  • 使用override配置会替换默认补全提供者,导致基础补全丢失
  • 全局variables变量会累积历史定义,导致类型判断错误
  • 点号匹配正则不准确,无法正确捕获输入点号后的变量名
  • 变量类型检测逻辑简单,无法覆盖常见赋值场景(如构造函数、表达式)

具体修改方案

1. 保留默认补全,添加自定义提供者

将autocompletion的override改为add,让自定义补全和默认补全共存:

<CodeMirror
  value={value}
  height="330px"
  width="1000px"
  extensions={[
    python(),
    indentUnit.of("    "),
    // 用add替代override,保留默认补全
    autocompletion({ add: [customCompletionProvider] }),
    onUpdateExtension,
  ]}
  onChange={onChange}
  theme={Theme}
/>

2. 修复自定义补全提供者逻辑

优化变量类型检测,使用局部变量避免累积,改进点号匹配逻辑:

const customCompletionProvider = (context) => {
  // 使用局部变量存储当前文档的变量类型,避免全局累积
  const variables = {};
  const code = context.state.doc.toString();

  // 优化变量类型检测正则,处理前后空格、构造函数等场景
  const variableDeclarationPattern = /(\w+)\s*=\s*(.+?)(?=\n|$)/g;
  let match;
  while ((match = variableDeclarationPattern.exec(code)) !== null) {
    const [_, varName, varValueRaw] = match;
    const varValue = varValueRaw.trim();
    
    // 字符串判断
    if (/^['"].*['"]$/.test(varValue)) {
      variables[varName] = "str";
    } 
    // 列表/元组/字典字面量
    else if (/^\[.*\]$/.test(varValue)) {
      variables[varName] = "list";
    } else if (/^\(.*\)$/.test(varValue) && !varValue.includes('=')) {
      variables[varName] = "tuple";
    } else if (/^\{.*\}$/.test(varValue)) {
      variables[varName] = "dict";
    }
    // 数字类型
    else if (/^[-+]?\d+$/.test(varValue)) {
      variables[varName] = "int";
    } else if (/^[-+]?\d*\.\d+$/.test(varValue)) {
      variables[varName] = "float";
    }
    // 构造函数(如str()、list())
    else if (/^(\w+)\(\s*\)$/.test(varValue)) {
      const typeMatch = varValue.match(/^(\w+)\(\s*\)$/);
      variables[varName] = typeMatch[1];
    }
  }

  // 匹配点号前的变量名(输入点号后触发)
  const dotMatch = context.matchBefore(/(\w+)\.$/);
  if (dotMatch) {
    const varName = dotMatch.text.slice(0, -1); // 去掉末尾的点号
    if (variables[varName]) {
      const methods = getMethodsForType(variables[varName]);
      return {
        from: dotMatch.from + varName.length + 1, // 点号后的位置
        options: methods.map(method => ({
          label: method,
          type: "method",
          info: `${variables[varName]} 方法`
        })),
      };
    }
  }

  // 基础关键字补全(仅在默认补全不足时补充)
  const word = context.matchBefore(/\w*/);
  if (!word || !word.text) return null;

  const basicSuggestions = [
    { label: "print", type: "function" },
    { label: "len", type: "function" },
    { label: "def", type: "function" },
    { label: "class", type: "class" },
    { label: "async", type: "keyword" },
    { label: "return", type: "keyword" },
    { label: "yield", type: "keyword" },
  ];

  return {
    from: word.from,
    options: basicSuggestions.filter(suggestion =>
      suggestion.label.startsWith(word.text)
    ),
  };
};

// 示例:返回对应类型的方法列表
const getMethodsForType = (type) => {
  const typeMethods = {
    str: ["capitalize", "lower", "upper", "strip", "split", "join", "replace"],
    list: ["append", "extend", "pop", "remove", "sort", "reverse", "index"],
    dict: ["keys", "values", "items", "get", "update", "pop"],
    int: ["bit_length", "to_bytes", "from_bytes"],
    float: ["is_integer", "as_integer_ratio"],
    tuple: ["count", "index"]
  };
  return typeMethods[type] || [];
};

3. 优化补全触发时机

修改onUpdateExtension,判断光标位置的前一个字符是否为点号,避免误触发:

const onUpdateExtension = EditorView.updateListener.of((update) => {
  if (update.docChanged) {
    const { state } = update.view;
    const cursorPos = state.selection.main.from;
    // 确保光标不在文档开头,且前一个字符是点号
    if (cursorPos > 0) {
      const charBefore = state.doc.sliceString(cursorPos - 1, cursorPos);
      if (charBefore === ".") {
        startCompletion(update.view);
      }
    }
  }
});

关键改进点

  • 用add替代override,保留CodeMirror默认的Python补全(如关键字、内置函数)
  • 局部变量存储当前文档的变量类型,避免历史定义干扰
  • 优化正则匹配,覆盖更多变量赋值场景(构造函数、表达式字面量)
  • 精准匹配点号前的变量名,确保输入点号后立即显示对应类型的方法
  • 调整补全触发逻辑,只在光标前是点号时触发补全

内容的提问来源于stack exchange,提问作者Effex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:23:09