LeetCode|力扣 智能C++语法智能提示

为 [LeetCode(力扣)中国站](https://leetcode.cn) 提供增强版的 C++ 自动补全、悬浮提示与跳转功能,**纯前端实现、无需后端服务器**,助力更高效刷题!

// ==UserScript==
// @name         LeetCode|力扣 智能C++语法智能提示
// @namespace    https://tampermonkey.net/
// @version      5.1.0
// @description  为 [LeetCode(力扣)中国站](https://leetcode.cn) 提供增强版的 C++ 自动补全、悬浮提示与跳转功能,**纯前端实现、无需后端服务器**,助力更高效刷题!
// @author       bigonion
// @match        https://leetcode.cn/problems/*
// @grant        unsafeWindow
// @license MIT
// ==/UserScript==

(function () {
  'use strict';

  /* ---------- 1. STATIC DICTIONARY ---------- */
  const cppDict = [
    { label:'int',  type:'keyword',  hover:'Signed 32-bit integer' },
    { label:'double',type:'keyword', hover:'Double-precision float' },
    { label:'char', type:'keyword',  hover:'8-bit character' },
    { label:'bool', type:'keyword',  hover:'Boolean true / false' },
    { label:'void', type:'keyword',  hover:'No return value' },
    { label:'auto', type:'keyword',  hover:'Type deduced by compiler (C++11)' },
    { label:'constexpr',type:'keyword',hover:'Compile-time constant (C++11)' },
    { label:'return', type:'keyword',  hover:'Return from current function' },
    { label:'for', type:'keyword',
      snippet:'for (int ${1:i}=0; ${1:i}<${2:n}; ++${1:i}) {\n\t$0\n}',
      hover:'Counting loop' },
    { label:'while', type:'keyword',
      snippet:'while (${1:cond}) {\n\t$0\n}',
      hover:'Loop while *cond* true' },
    { label:'if', type:'keyword',
      snippet:'if (${1:cond}) {\n\t$0\n}',
      hover:'Conditional branch' },
    { label:'else', type:'keyword', hover:'Alternative branch' },
    { label:'main', type:'snippet',
      snippet:`int main() {
\tios::sync_with_stdio(false);
\tcin.tie(nullptr);
\t$0
\treturn 0;
}`, hover:'Contest main() with fast I/O' },
    { label:'vector', type:'class',
      snippet:'vector<${1:int}> ${2:v};',
      hover:'\`vector<T>\` — dynamic array (`<vector>`)' },
    { label:'string', type:'class',
      hover:'\`string\` — mutable text (`<string>`)' },
    { label:'unordered_map',type:'class',
      hover:'Hash table (`<unordered_map>`)' },
    { label:'queue',type:'class',hover:'FIFO queue (`<queue>`)' },
    { label:'priority_queue',type:'class',
      hover:'Binary heap (`<queue>`)' },
    { label:'stack',type:'class',hover:'LIFO stack (`<stack>`)' },
    { label:'sort',type:'function',
      snippet:'sort(${1:begin}, ${2:end});',
      hover:'\`sort(first,last)\` ascending' },
    { label:'reverse',type:'function',
      snippet:'reverse(${1:begin}, ${2:end});',
      hover:'Reverse range in-place' },
    { label:'max',type:'function',snippet:'max(${1:a}, ${2:b});',
      hover:'Return larger value' },
    { label:'min',type:'function',snippet:'min(${1:a}, ${2:b});',
      hover:'Return smaller value' },
    { label:'accumulate',type:'function',
      snippet:'accumulate(${1:begin}, ${2:end}, ${3:0});',
      hover:'Sum range (`<numeric>`)' },
    { label:'lower_bound',type:'function',
      snippet:'lower_bound(${1:b}, ${2:e}, ${3:v});',
      hover:'First ≥ val (binary search)' },
    { label:'upper_bound',type:'function',
      snippet:'upper_bound(${1:b}, ${2:e}, ${3:v});',
      hover:'First > val (binary search)' },
    { label:'abs',type:'function',snippet:'abs(${1:x});',
      hover:'Absolute value' },
    { label:'pow',type:'function',snippet:'pow(${1:b}, ${2:e});',
      hover:'Power (`<cmath>`)' },
    { label:'sqrt',type:'function',snippet:'sqrt(${1:x});',
      hover:'Square root (`<cmath>`)' },
    { label:'cout',type:'function',
      snippet:'cout << ${1:msg} << endl;',
      hover:'Standard output stream' },
    { label:'cin', type:'function', hover:'Standard input stream' },
    { label:'getline',type:'function',
      snippet:'getline(cin, ${1:str});',
      hover:'Read full line' },
    { label:'memset',type:'function',
      snippet:'memset(${1:ptr}, 0, sizeof(${1:ptr}));',
      hover:'Fill bytes (`<cstring>`)' },
    { label:'memcpy',type:'function',
      snippet:'memcpy(${1:dst}, ${2:src}, sizeof(${1:dst}));',
      hover:'Copy bytes (`<cstring>`)' }
  ];

  /* ---------- 2. WAIT FOR MONACO ---------- */
  const ready = f => new Promise(r=>{const t=setInterval(()=>f()&&(clearInterval(t),r()),250);});
  ready(()=>unsafeWindow.monaco && unsafeWindow.monaco.editor.getModels().length).then(init);

  function init(){
    const monaco = unsafeWindow.monaco;
    const model  = monaco.editor.getModels()[0];
    if (!['cpp','c'].includes(model.getLanguageId())) return;
    if (model.getLanguageId()!=='cpp') monaco.editor.setModelLanguage(model,'cpp');

    /* --- 3. Build variable & function index --- */
    let varTable=new Map();  // name -> {type,line,col}
    let fnTable =new Map();  // name -> {line,col}

    const VAR_RE = /^\s*(?:const\s+)?([\w:<>\s*&]+?)\s+([A-Za-z_]\w*)\s*(?:[=;\[,]|$)/;
    const FN_RE  = /^\s*(?:template<[^>]+>\s*)?([\w:<>\s*&]+?)\s+([A-Za-z_]\w*)\s*\([^;{]*\)\s*\{/;

    const buildIndex = () => {
      varTable.clear(); fnTable.clear();
      model.getLinesContent().forEach((line,i)=>{
        let m = VAR_RE.exec(line);
        if(m) varTable.set(m[2],{type:m[1].trim().replace(/\s+/g,' '),line:i+1,col:line.indexOf(m[2])+1});
        m = FN_RE.exec(line);
        if(m) fnTable.set(m[2],{line:i+1,col:line.indexOf(m[2])+1});
      });
    };
    buildIndex();
    model.onDidChangeContent(buildIndex);   // ✅ FIXED api

    /* --- 4. Completion --- */
    monaco.languages.registerCompletionItemProvider('cpp',{
      provideCompletionItems:(mdl,pos)=>{
        const w=mdl.getWordUntilPosition(pos);
        const pre=w.word;
        const r={startLineNumber:pos.lineNumber,endLineNumber:pos.lineNumber,
                 startColumn:w.startColumn,endColumn:w.endColumn};
        const out=[]; const seen=new Set();
        for(const x of cppDict){
          if(pre && !x.label.startsWith(pre)) continue;
          if(seen.has(x.label)) continue; seen.add(x.label);
          out.push({
            label:x.label, range:r,
            kind:{keyword:monaco.languages.CompletionItemKind.Keyword,
                  function:monaco.languages.CompletionItemKind.Function,
                  class:monaco.languages.CompletionItemKind.Class,
                  snippet:monaco.languages.CompletionItemKind.Snippet}[x.type],
            insertText:x.snippet||x.label,
            insertTextRules:x.snippet?monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet:undefined,
            documentation:x.hover?{value:x.hover}:undefined,
            sortText:'zz_'+x.label
          });
        }
        return{suggestions:out};
      }
    });

    /* --- 5. Hover (dict + variables) --- */
    monaco.languages.registerHoverProvider('cpp',{
      provideHover:(mdl,pos)=>{
        const w=mdl.getWordAtPosition(pos); if(!w) return null;
        const dict = cppDict.find(x=>x.label===w.word && x.hover);
        if(dict) return mkHover(dict.hover,pos,w);
        const v = varTable.get(w.word);
        if(v) return mkHover(`\`${v.type} ${w.word}\``,pos,w);
        return null;
      }
    });
    function mkHover(text,pos,w){
      return{contents:[{value:text}],
        range:{startLineNumber:pos.lineNumber,endLineNumber:pos.lineNumber,
               startColumn:w.startColumn,endColumn:w.endColumn}};
    }

    /* --- 6. Definition (functions) --- */
    monaco.languages.registerDefinitionProvider('cpp',{
      provideDefinition:(mdl,pos)=>{
        const w=mdl.getWordAtPosition(pos); if(!w) return null;
        const def=fnTable.get(w.word);
        if(!def) return null;
        return{uri:mdl.uri,range:{startLineNumber:def.line,endLineNumber:def.line,
                                  startColumn:def.col,endColumn:def.col+w.word.length}};
      }
    });

    console.log('[C++] Booster V5.1 ready – vars:',varTable.size,'funcs:',fnTable.size);
  }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址