diff --git a/.vscode/launch.json b/.vscode/launch.json index 2bed8921e2803711f9c40a8be24fb242600ae42e..76cd0de96e1df539eb91c23192cab2abbf15194f 100755 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,12 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", + "env": { + "NODE_ENV": "dev" + }, "args": [ "--extensionDevelopmentPath=${workspaceFolder}", - // "--disable-extensions" + "--disable-extensions" ] }, { diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c02960963d0d844310becadda23fa24e44abad2..37335f1524f3321bc56d225f23340f8e614c3712 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 各版本更新说明 +### 1.3.0 + +- 修复:[JS 原补全项消失问题](https://gitee.com/Program-in-Chinese/vscode_Chinese_Input_Assistant/issues/I1Q34I) +- 修复:[C++ 语言插件不兼容问题](https://gitee.com/Program-in-Chinese/vscode_Chinese_Input_Assistant/issues/I1PWE7) + ### 1.2.1 修复问题: [补全项重复](https://gitee.com/Program-in-Chinese/vscode_Chinese_Input_Assistant/issues/I1PUZX) diff --git a/README.md b/README.md index 02267546074a7a19ae6b90171830bb5083b93a7c..06ea1d4a8c2e8d76f23bf687ef724d44dd4b30dc 100755 --- a/README.md +++ b/README.md @@ -44,28 +44,12 @@ ![演示](截图/输入法_五笔四码.png) -支持各种编程语言,全拼下已实测过的: - -- C# - -![演示](截图/演示_c.png) - -- Haskell - -![演示](截图/演示_Haskell.png) - -- Java - -![演示](截图/演示_Java.png) +与各种编程语言的现有支持插件兼容,全拼下已实测过的: - JavaScript ![演示](截图/演示_JS.png) -- Kotlin - -![演示](截图/演示_Kotlin.png) - - PHP 对 $ 开头的变量名,直接输入拼音即有提示: @@ -76,14 +60,14 @@ ![演示](截图/演示_Python.png) -- Swift - -![演示](截图/演示_Swift.png) - - TypeScript ![演示](截图/演示_TS.png) +当无编程语言支持插件时,也支持当前文件中的中文字段补全: + +![演示](截图/演示_Kotlin.png) + 同样支持中英混合命名: ![演示](截图/演示_中英混合.png) @@ -96,6 +80,4 @@ ## [版本更新说明](CHANGELOG.md) -## 已知问题 - -暂无 +## [已知问题](文档/已知问题.md) diff --git a/lib/vscode.js b/lib/vscode.js new file mode 100644 index 0000000000000000000000000000000000000000..d74a401ee78a1fa2bc6a8aa12a6e20c73113b350 --- /dev/null +++ b/lib/vscode.js @@ -0,0 +1,44 @@ +var vscode = require('vscode') +var R = require('ramda') + +exports.获得当前输入词 = function 获得当前输入词() { + // 我们需要的是文本被编辑后的情况 而不是编辑前的情况 + // 在某些地方调用 会意外的 获得文本被编辑前的情况 + // 所以加个定时器 确保函数在文本修改后执行 + // 这样函数就变成了异步的 于是加了Promise + return new Promise((res, rej) => { + setTimeout(() => { + var editor = vscode.window.activeTextEditor + if (!editor) return res(null) + + var position = editor.selections[0].anchor; + var document = editor.document + var range = document.getWordRangeAtPosition(position) + + if (range == null) return res(null) + + var 当前输入词 = document.getText(range) + return res(当前输入词) + }, 0) + }) +} +exports.获得当前文件后缀名 = function 获得当前文件后缀名({ document }) { + return R.last(document.fileName.split('.')) +} +exports.获得文档内容 = function 获得文档内容(document, position) { + var 总行数 = document.lineCount + var 当前行 = position.line + var 文档内容 = "" + for (var i = 0; i < 总行数; i++) { + if (i != 当前行) + 文档内容 += document.lineAt(i).text + "\n"; + } + return 文档内容 +} +exports.构造文本补全项 = function 构造文本补全项({ 标签, 内容 }) { + var r = new vscode.CompletionItem(标签) + r.label = 标签 + r.kind = 'text' + r.insertText = 内容 + return r +} diff --git "a/\344\272\224\347\254\224\350\276\223\345\205\245\346\263\225.js" "b/lib/\344\272\224\347\254\224.js" similarity index 70% rename from "\344\272\224\347\254\224\350\276\223\345\205\245\346\263\225.js" rename to "lib/\344\272\224\347\254\224.js" index c10470b67f3d519551019dcc0ef09dd0a12428c6..1c92b2fde16efaeb71f7c7718f6337791b614cd7 100644 --- "a/\344\272\224\347\254\224\350\276\223\345\205\245\346\263\225.js" +++ "b/lib/\344\272\224\347\254\224.js" @@ -4,7 +4,7 @@ function 五笔(文字, 提示方式) { if (!文字) return ""; var 键码 = ""; var 非汉字字符计数 = 0 - var 版本=提示方式.substr(2,2); + var 版本 = 提示方式.substr(2, 2); for (var i = 0, len = 文字.length; i < len; i++) { var 字 = 文字.substr(i, 1); var unicode = 字.charCodeAt(0); @@ -12,23 +12,21 @@ function 五笔(文字, 提示方式) { if (unicode > 40869 || unicode < 19968) { 键码 += 字 非汉字字符计数++ - } else if (提示方式.indexOf("全码")!=-1) { - 键码 += 首字母大写(码表.取码(字,版本)) - } else if (提示方式.indexOf("四码")!=-1) { + } else if (提示方式.indexOf("全码") != -1) { + 键码 += 首字母大写(码表.取码(字, 版本)) + } else if (提示方式.indexOf("四码") != -1) { if (文字.length - 非汉字字符计数 == 1) { - 键码 += 码表.取码(字,版本) + 键码 += 码表.取码(字, 版本) } else if (文字.length - 非汉字字符计数 == 2) { - 键码 += 码表.取码(字,版本).slice(0, 2) + 键码 += 码表.取码(字, 版本).slice(0, 2) } else if (文字.length - 非汉字字符计数 == 3) { - 键码 += 码表.取码(字,版本).slice(0, i - 非汉字字符计数 < 2 ? 1 : 2) + 键码 += 码表.取码(字, 版本).slice(0, i - 非汉字字符计数 < 2 ? 1 : 2) } else if (文字.length - 非汉字字符计数 >= 4 && (i - 非汉字字符计数 < 3 || i + 1 - 非汉字字符计数 == 文字.length)) { - 键码 += 码表.取码(字,版本).slice(0, 1) + 键码 += 码表.取码(字, 版本).slice(0, 1) } } } return 键码; - - } function 首字母大写(拼音) { if (拼音.length > 0) { diff --git "a/lib/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225.js" "b/lib/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225.js" index dc598177758347cbd7644f579e7a2053836092e6..7a7539df19f08dc23b835f98011ba552950f8900 100644 --- "a/lib/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225.js" +++ "b/lib/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225.js" @@ -1 +1,11 @@ exports.转换为大写 = 字符串 => 字符串.toLocaleUpperCase() +exports.包含中文 = function 包含中文(str) { + return /.*[\u4e00-\u9fa5]+.*$/.test(str) +} +exports.是纯字母 = function 是纯字母(str) { + return /[A-Za-z]/.test(str) +} +exports.查找词组 = function 查找词组(s) { + var wordPattern = /(-?\d*\.\d\w*)|([^\`\~\!\@\^\&\*\(\)\-\#\?\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s?。,、;:?…—·ˉˇ¨“”~〃|《》〔〕(),]+)/g; + return Array.from(new Set(s.match(wordPattern))) +} diff --git a/bopomofo.js "b/lib/\346\213\274\351\237\263.js" similarity index 100% rename from bopomofo.js rename to "lib/\346\213\274\351\237\263.js" diff --git "a/lib/\346\225\260\347\273\204\346\211\251\345\261\225.js" "b/lib/\346\225\260\347\273\204\346\211\251\345\261\225.js" index 50f8042caa62ee07234ad5bd2de148770975a7a6..016627cf982a27b548da25a1cea889f9ec0edb99 100644 --- "a/lib/\346\225\260\347\273\204\346\211\251\345\261\225.js" +++ "b/lib/\346\225\260\347\273\204\346\211\251\345\261\225.js" @@ -1 +1,17 @@ exports.多重笛卡尔积 = arr => arr.reduce((as, bs) => as.map(a => bs.map(b => [...a, b])).flat(), [[]]) +exports.数组去重 = (判别式, 数组) => { + var 包含 = (判别式, 项, 数组) => { + for (var i = 0; i < 数组.length; i++) { + if (判别式(数组[i], 项)) + return true + } + return false + } + + var r = [] + for (var i = 0; i < 数组.length; i++) { + if (!包含(判别式, 数组[i], r)) + r.push(数组[i]) + } + return r +} diff --git "a/lib/\346\227\245\345\277\227.js" "b/lib/\346\227\245\345\277\227.js" new file mode 100644 index 0000000000000000000000000000000000000000..4f020f15766206c4525e9ea2dba9ff7d6bbdb124 --- /dev/null +++ "b/lib/\346\227\245\345\277\227.js" @@ -0,0 +1,6 @@ +exports.log = (...s) => { + if (process.env.NODE_ENV == 'dev') { + console.log(...s.map(a => JSON.stringify(a))) + } + return s[s.length - 1] +} diff --git "a/lib/\347\231\276\345\272\246\346\220\234\347\264\242\350\201\224\346\203\263.js" "b/lib/\347\231\276\345\272\246\346\220\234\347\264\242\350\201\224\346\203\263.js" index f2e770b91fcefbcc776c02a7d4faa85821082594..b30f124549fc3f89ce5ff97aec83d8949f0a6da1 100644 --- "a/lib/\347\231\276\345\272\246\346\220\234\347\264\242\350\201\224\346\203\263.js" +++ "b/lib/\347\231\276\345\272\246\346\220\234\347\264\242\350\201\224\346\203\263.js" @@ -1,6 +1,6 @@ const http = require('./http') -module.exports = 字符串 => async 数量 => { +module.exports = async (字符串, 数量 = 5) => { if (字符串.indexOf('\r') != -1 || 字符串.indexOf('\n') != -1) return [] // console.log(字符串) var url = `https://www.baidu.com/sugrec?prod=pc&from=pc_web&wd=${字符串}` diff --git "a/lib/\350\216\267\345\276\227\344\270\255\346\226\207\345\255\227\347\254\246\350\241\250\347\244\272.js" "b/lib/\350\216\267\345\276\227\344\270\255\346\226\207\345\255\227\347\254\246\350\241\250\347\244\272.js" new file mode 100644 index 0000000000000000000000000000000000000000..6ce4aefe7d80654d2ec35f188717bfc395095321 --- /dev/null +++ "b/lib/\350\216\267\345\276\227\344\270\255\346\226\207\345\255\227\347\254\246\350\241\250\347\244\272.js" @@ -0,0 +1,20 @@ +var 五笔 = require('./五笔.js') +var 拼音A = require('./拼音.js') +var 拼音 = require('pinyin') +var { 多重笛卡尔积 } = require('./数组扩展.js') +var { 转换为大写 } = require('./字符串扩展') + +module.exports = function 获得中文字符表示({ 表示方法, 文本, 选项 }) { + if (表示方法.indexOf("五笔") != -1) { + return [五笔.五笔(文本, 表示方法)] + } + if (表示方法.indexOf('拼音')) { + var 结果 = null + 结果 = 拼音(文本, { heteronym: 选项.使用多音字 == 'yes', style: 拼音.STYLE_NORMAL }) + 结果 = 结果.map(a => a.map(a => 转换为大写(a[0]) + a.substring(1))) + 结果 = 多重笛卡尔积(结果).map(a => a.join('')) + if (表示方法 != "全拼") + 结果 = 结果.map(a => 拼音A.双拼转换(a, 表示方法)) + return 结果 + } +} diff --git "a/lib/\350\260\267\346\255\214\350\276\223\345\205\245\346\263\225API.js" "b/lib/\350\260\267\346\255\214\350\276\223\345\205\245\346\263\225API.js" index 220b0b15adc36ce756ff67d25917cae4522ce7fe..2f4fde96c045e7024381e04f197fe4564391ddab 100644 --- "a/lib/\350\260\267\346\255\214\350\276\223\345\205\245\346\263\225API.js" +++ "b/lib/\350\260\267\346\255\214\350\276\223\345\205\245\346\263\225API.js" @@ -1,7 +1,7 @@ const http = require('./http') // api使用来自 https://github.com/zyctree/vscode-google-pinyin -module.exports = 字符串 => async 数量 => { +module.exports = async (字符串, 数量 = 5) => { if (字符串.indexOf('\r') != -1 || 字符串.indexOf('\n') != -1) return [] // console.log(字符串) var url = `http://inputtools.google.com/request?text=${字符串}&itc=zh-t-i0-pinyin&num=${数量}&cp=0&cs=1&ie=utf-8&oe=utf-8&app=demopage` diff --git a/package-lock.json b/package-lock.json index 110cb8fdd1907b9fadf2bf97af3931271bf92810..af6054e15d19a3ee3f6563cdc3f977c2d8dde7c5 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ChineseInputAssistant", - "version": "1.2.1", + "version": "1.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c72f35db4ee47a0830753cc7739e584f9e77a5a9..db15b3179e7f7c4878a002b346cb86a90ba43e5b 100755 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "ChineseInputAssistant", "displayName": "中文代码快速补全", "description": "中文标识符(变量、方法名等)无需切换中文输入法即有补全提示", - "version": "1.2.1", + "version": "1.3.0", "publisher": "CodeInChinese", "engines": { "vscode": "^1.38.0" @@ -14,14 +14,8 @@ "*", "onCommand:插件命令" ], - "main": "./插件.js", + "main": "./入口.js", "contributes": { - "commands": [ - { - "command": "插件命令", - "title": "中文插件" - } - ], "configuration": { "title": "中文代码快速补全", "properties": { @@ -53,7 +47,7 @@ ], "enumDescriptions": [ "不使用输入法", - "谷歌拼音输入法", + "谷歌拼音输入法(需能访问谷歌api)", "百度搜索联想" ] }, diff --git a/util.js b/util.js deleted file mode 100755 index 6feb47b8713be06f6d0301655d945a772d822b28..0000000000000000000000000000000000000000 --- a/util.js +++ /dev/null @@ -1,259 +0,0 @@ -const fs = require('fs'); -const os = require('os'); -const path = require('path'); -const vscode = require('vscode'); -const exec = require('child_process').exec; - -const util = { - /** - * 获取当前所在工程根目录,有3种使用方法:
- * getProjectPath(uri) uri 表示工程内某个文件的路径
- * getProjectPath(document) document 表示当前被打开的文件document对象
- * getProjectPath() 会自动从 activeTextEditor 拿document对象,如果没有拿到则报错 - * @param {*} document - */ - getProjectPath(document) { - if (!document) { - document = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document : null; - } - if (!document) { - this.showError('当前激活的编辑器不是文件或者没有文件被打开!'); - return ''; - } - const currentFile = (document.uri ? document.uri : document).fsPath; - let projectPath = null; - - let workspaceFolders = vscode.workspace.workspaceFolders.map(item => item.uri.path); - // 由于存在Multi-root工作区,暂时没有特别好的判断方法,先这样粗暴判断 - // 如果发现只有一个根文件夹,读取其子文件夹作为 workspaceFolders - if (workspaceFolders.length == 1 && workspaceFolders[0] === vscode.workspace.rootPath) { - const rootPath = workspaceFolders[0]; - var files = fs.readdirSync(rootPath); - workspaceFolders = files.filter(name => !/^\./g.test(name)).map(name => path.resolve(rootPath, name)); - // vscode.workspace.rootPath会不准确,且已过时 - // return vscode.workspace.rootPath + '/' + this._getProjectName(vscode, document); - } - workspaceFolders.forEach(folder => { - if (currentFile.indexOf(folder) === 0) { - projectPath = folder; - } - }) - if (!projectPath) { - this.showError('获取工程根路径异常!'); - return ''; - } - return projectPath; - }, - /** - * 获取当前工程名 - */ - getProjectName: function (projectPath) { - return path.basename(projectPath); - }, - getPluginPath() { - - }, - /** - * 将一个单词首字母大写并返回 - * @param {*} word 某个字符串 - */ - upperFirstLetter: function (word) { - return (word || '').replace(/^\w/, m => m.toUpperCase()); - }, - /** - * 将一个单词首字母转小写并返回 - * @param {*} word 某个字符串 - */ - lowerFirstLeter: function (word) { - return (word || '').replace(/^\w/, m => m.toLowerCase()); - }, - /** - * 全局日志开关,发布时可以注释掉日志输出 - */ - log: function (...args) { - console.log(...args); - }, - /** - * 全局日志开关,发布时可以注释掉日志输出 - */ - error: function (...args) { - console.error(...args); - }, - /** - * 弹出错误信息 - */ - showError: function (info) { - vscode.window.showErrorMessage(info); - }, - /** - * 弹出提示信息 - */ - showInfo: function (info) { - vscode.window.showInformationMessage(info); - }, - findStrInFolder: function (folderPath, str) { - - }, - /** - * 从某个文件里面查找某个字符串,返回第一个匹配处的行与列,未找到返回第一行第一列 - * @param filePath 要查找的文件 - * @param reg 正则对象,最好不要带g,也可以是字符串 - */ - findStrInFile: function (filePath, reg) { - const content = fs.readFileSync(filePath, 'utf-8'); - reg = typeof reg === 'string' ? new RegExp(reg, 'm') : reg; - // 没找到直接返回 - if (content.search(reg) < 0) return { row: 0, col: 0 }; - const rows = content.split(os.EOL); - // 分行查找只为了拿到行 - for (let i = 0; i < rows.length; i++) { - let col = rows[i].search(reg); - if (col >= 0) { - return { row: i, col }; - } - } - return { row: 0, col: 0 }; - }, - /** - * 获取某个字符串在文件里第一次出现位置的范围, - */ - getStrRangeInFile: function (filePath, str) { - var pos = this.findStrInFile(filePath, str); - return new vscode.Range(new vscode.Position(pos.row, pos.col), new vscode.Position(pos.row, pos.col + str.length)); - }, - /** - * 简单的检测版本大小 - */ - checkVersion: function (version1, version2) { - version1 = parseInt(version1.replace(/\./g, '')); - version2 = parseInt(version2.replace(/\./g, '')); - return version1 > version2; - }, - /** - * 获取某个扩展文件绝对路径 - * @param context 上下文 - * @param relativePath 扩展中某个文件相对于根目录的路径,如 images/test.jpg - */ - getExtensionFileAbsolutePath: function (context, relativePath) { - return path.join(context.extensionPath, relativePath); - }, - /** - * 获取某个扩展文件相对于webview需要的一种特殊路径格式 - * 形如:vscode-resource:/Users/toonces/projects/vscode-cat-coding/media/cat.gif - * @param context 上下文 - * @param relativePath 扩展中某个文件相对于根目录的路径,如 images/test.jpg - */ - getExtensionFileVscodeResource: function (context, relativePath) { - const diskPath = vscode.Uri.file(path.join(context.extensionPath, relativePath)); - return diskPath.with({ scheme: 'vscode-resource' }).toString(); - }, - /** - * 在Finder中打开某个文件或者路径 - */ - openFileInFinder: function (filePath) { - if (!fs.existsSync(filePath)) { - this.showError('文件不存在:' + filePath); - } - // 如果是目录,直接打开就好 - if (fs.statSync(filePath).isDirectory()) { - exec(`open ${filePath}`); - } else { - // 如果是文件,要分开处理 - const fileName = path.basename(filePath); - filePath = path.dirname(filePath); - // 这里有待完善,还不知道如何finder中如何选中文件 - exec(`open ${filePath}`); - } - }, - /** - * 在vscode中打开某个文件 - * @param {*} path 文件绝对路径 - * @param {*} text 可选,如果不为空,则选中第一处匹配的对应文字 - */ - openFileInVscode: function (path, text) { - let options = undefined; - if (text) { - const selection = this.getStrRangeInFile(path, text); - options = { selection }; - } - vscode.window.showTextDocument(vscode.Uri.file(path), options); - }, - /** - * 用JD-GUI打开jar包 - */ - openJarByJdGui: function (jarPath) { - // 如何选中文件有待完善 - const jdGuiPath = vscode.workspace.getConfiguration().get('eggHelper.jdGuiPath'); - if (!jdGuiPath) { - this.showError('JD-GUI路径不能为空!'); - return; - } - if (!fs.existsSync(jdGuiPath)) { - this.showError('您还没有安装JD-GUI,请安装完后到vscode设置里面找到HSF助手并进行路径配置。'); - return; - } - if (!fs.existsSync(jarPath)) { - this.showError('jar包未找到:' + jarPath); - return; - } - exec(`open ${jarPath} -a ${jdGuiPath}`); - }, - /** - * 使用默认浏览器中打开某个URL - */ - openUrlInBrowser: function (url) { - exec(`open '${url}'`); - }, - /** - * 递归遍历清空某个资源的require缓存 - * @param {*} absolutePath - */ - clearRequireCache(absolutePath) { - const root = require.cache[absolutePath]; - if (!root) return; - if (root.children) { - // 如果有子依赖项,先清空依赖项的缓存 - root.children.forEach(item => { - this.clearRequireCache(item.id); - }); - } - delete require.cache[absolutePath]; - }, - /** - * 动态require,和普通require不同的是,加载之前会先尝试删除缓存 - * @param {*} modulePath - */ - dynamicRequire(modulePath) { - this.clearRequireCache(modulePath); - return require(modulePath); - }, - /** - * 读取properties文件 - * @param {*} filePath - */ - readProperties(filePath) { - const content = fs.readFileSync(filePath, 'utf-8'); - let rows = content.split(os.EOL); - rows = rows.filter(row => row && row.trim() && !/^#/.test(row)); - const result = {}; - rows.forEach(row => { - let temp = row.split('='); - result[temp[0].trim()] = temp[1].trim(); - }); - return result; - }, - /** - * 比较2个对象转JSON字符串后是否完全一样 - * 特别注意,由于JS遍历对象的无序性(部分浏览器是按照添加顺序遍历的)导致同样的对象, - * 转成JSON串之后反而不一样,所以这里采用其它方式实现。 - * @param {*} obj1 - * @param {*} obj2 - */ - jsonEquals(obj1, obj2) { - let s1 = this.formatToSpecialJSON(obj1, '', true); - let s2 = this.formatToSpecialJSON(obj2, '', true); - return s1 === s2; - } -}; - -module.exports = util; diff --git a/vsc-extension-quickstart.md b/vsc-extension-quickstart.md deleted file mode 100755 index e6da2a5c8e5a2590cb867d8a5fc207800b190639..0000000000000000000000000000000000000000 --- a/vsc-extension-quickstart.md +++ /dev/null @@ -1,39 +0,0 @@ -# Welcome to your VS Code Extension - -## What's in the folder - -* This folder contains all of the files necessary for your extension. -* `package.json` - this is the manifest file in which you declare your extension and command. - * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. -* `extension.js` - this is the main file where you will provide the implementation of your command. - * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. - * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. - -## Get up and running straight away - -* Press `F5` to open a new window with your extension loaded. -* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. -* Set breakpoints in your code inside `extension.js` to debug your extension. -* Find output from your extension in the debug console. - -## Make changes - -* You can relaunch the extension from the debug toolbar after changing code in `extension.js`. -* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. - -## Explore the API - -* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. - -## Run tests - -* Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. -* Press `F5` to run the tests in a new window with your extension loaded. -* See the output of the test result in the debug console. -* Make changes to `src/test/suite/extension.test.js` or create new test files inside the `test/suite` folder. - * The provided test runner will only consider files matching the name pattern `**.test.ts`. - * You can create folders inside the `test` folder to structure your tests any way you want. -## Go further - - * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. - * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). diff --git "a/\344\276\233\346\265\213\350\257\225/cpp/hello.cpp" "b/\344\276\233\346\265\213\350\257\225/cpp/hello.cpp" new file mode 100644 index 0000000000000000000000000000000000000000..fc088cced4efba3a7c1538cd95545410aeb3970f --- /dev/null +++ "b/\344\276\233\346\265\213\350\257\225/cpp/hello.cpp" @@ -0,0 +1,19 @@ +#include +#include +#include + +/* +源自: https://code.visualstudio.com/docs/cpp/config-clang-mac#_add-hello-world-source-code-file +*/ +using namespace std; + +int main() +{ + vector msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"}; + + for (const string& word : msg) + { + cout << word << " "; + } + cout << endl; +} \ No newline at end of file diff --git "a/\344\276\233\346\265\213\350\257\225/cpp/main.cpp" "b/\344\276\233\346\265\213\350\257\225/cpp/main.cpp" index 64d0c7ad764f78abe0133f0c4eddfd68157be78a..942343176de34a5826da1fa3298e92bb3389674c 100644 --- "a/\344\276\233\346\265\213\350\257\225/cpp/main.cpp" +++ "b/\344\276\233\346\265\213\350\257\225/cpp/main.cpp" @@ -5,6 +5,8 @@ using namespace std; int main() { Circle 椭圆(3); + Circle oval(3); + // 输入 tuo 补全为 椭圆 再输入 点 return 1; diff --git "a/\344\276\233\346\265\213\350\257\225/js/index.js" "b/\344\276\233\346\265\213\350\257\225/js/index.js" index 585b5cff055bfacd24918d0cad64d59beda9a916..f4535ab04965c7a0b8a790e7e64429c3ab2edc70 100644 --- "a/\344\276\233\346\265\213\350\257\225/js/index.js" +++ "b/\344\276\233\346\265\213\350\257\225/js/index.js" @@ -3,6 +3,19 @@ import lib_esm from './lib_esm' var lib_node = require('./lib_node') var 中文变量 = 1 +function 加法() { } +function add() { } + +零蛋 = 0 +zero = 0 + +战国时代 = 1 + +class 小类 { } +class aClass { } + +多重笛卡尔积 = 0 + // 输入 lib_esm.zw // 输入 lib_node.zw // 输入 zw diff --git "a/\345\205\245\345\217\243.js" "b/\345\205\245\345\217\243.js" new file mode 100644 index 0000000000000000000000000000000000000000..a7471db3d6005fd765157ff1ffeb3f0acd2aed98 --- /dev/null +++ "b/\345\205\245\345\217\243.js" @@ -0,0 +1,9 @@ +var vscode = require('vscode') +var 补全实现 = require('./补全实现') + +function activate(context) { + console.log('恭喜,插件已激活') + 补全实现(context) +} + +exports.activate = activate diff --git "a/\346\210\252\345\233\276/\346\274\224\347\244\272_Haskell.png" "b/\346\210\252\345\233\276/\346\274\224\347\244\272_Haskell.png" deleted file mode 100644 index a4a44d32a05d367c5af94d38d99a4403b2de35a7..0000000000000000000000000000000000000000 Binary files "a/\346\210\252\345\233\276/\346\274\224\347\244\272_Haskell.png" and /dev/null differ diff --git "a/\346\210\252\345\233\276/\346\274\224\347\244\272_Java.png" "b/\346\210\252\345\233\276/\346\274\224\347\244\272_Java.png" deleted file mode 100644 index 7858d3aed4b5c346f4255d12ea2d1e7b1e93b1fc..0000000000000000000000000000000000000000 Binary files "a/\346\210\252\345\233\276/\346\274\224\347\244\272_Java.png" and /dev/null differ diff --git "a/\346\210\252\345\233\276/\346\274\224\347\244\272_Swift.png" "b/\346\210\252\345\233\276/\346\274\224\347\244\272_Swift.png" deleted file mode 100644 index bb97d6a4c1657ebb9ac34a77e09fc6fe36c2fb69..0000000000000000000000000000000000000000 Binary files "a/\346\210\252\345\233\276/\346\274\224\347\244\272_Swift.png" and /dev/null differ diff --git "a/\346\210\252\345\233\276/\346\274\224\347\244\272_c.png" "b/\346\210\252\345\233\276/\346\274\224\347\244\272_c.png" deleted file mode 100644 index b7f0e0026a3eff0eefcffdb4f80edda76728e664..0000000000000000000000000000000000000000 Binary files "a/\346\210\252\345\233\276/\346\274\224\347\244\272_c.png" and /dev/null differ diff --git "a/\346\217\222\344\273\266.js" "b/\346\217\222\344\273\266.js" deleted file mode 100755 index 9b4db9585048de06fdce941c27887dc4d19db696..0000000000000000000000000000000000000000 --- "a/\346\217\222\344\273\266.js" +++ /dev/null @@ -1,41 +0,0 @@ -// The module 'vscode' contains the VS Code extensibility API -// Import the module and reference it with the alias vscode in your code below -const vscode = require('vscode'); -// const util = require('./util'); -// this method is called when your extension is activated -// your extension is activated the very first time the command is executed - -/** - * @param {vscode.ExtensionContext} context - */ -function activate(context) { - - // Use the console to output diagnostic information (console.log) and errors (console.error) - // This line of code will only be executed once when your extension is activated - console.log('恭喜,插件已激活'); - require('./补全实现')(context); - // The command has been defined in the package.json file - // Now provide the implementation of the command with registerCommand - // The commandId parameter must match the command field in package.json - let disposable = vscode.commands.registerCommand('插件命令', function () { - // The code you place here will be executed every time your command is executed - - // Display a message box to the user - vscode.window.showInformationMessage('喵'); - }); - - context.subscriptions.push(disposable); -} - - - -exports.activate = activate; - -// this method is called when your extension is deactivated -function deactivate() { } - -module.exports = { - activate, - deactivate -} - diff --git "a/\346\226\207\346\241\243/\345\212\237\350\203\275.md" "b/\346\226\207\346\241\243/\345\212\237\350\203\275.md" new file mode 100644 index 0000000000000000000000000000000000000000..e738dba7d7936ceb59cc27499b019273ce957654 --- /dev/null +++ "b/\346\226\207\346\241\243/\345\212\237\350\203\275.md" @@ -0,0 +1,219 @@ +## 功能简述 + +在不影响 VS Code 的现有代码补全功能的前提下,不用切换到第三方中文输入法,就可以通过拼音等方式获得对应的中文代码补全。 + +## 术语表 + +参考:[VSC IntelliSense 官方文档](https://code.visualstudio.com/docs/editor/intellisense) + +| 中文 | 英文 | 简述 | +| ------------- | ------------- | ------------- | +| 代码补全 | code completion | | +| 触发字符 | trigger character | 比如 JavaScript 中的 . | +| 建议弹窗 | suggestions widget | 光标下方的包含建议补全项的窗口 | +| 关键词 | keyword | 编程语言语法中的保留关键词,如 [JS](https://www.w3schools.com/js/js_reserved.asp)中的 const,continue 等 | +| 标识符 | identifier | 关键词之外的代码内容,包括变量、方法、类名等等 | +| 字段 | | 包括标识符、注释中的中文字段 + +关键词、标识符分类: +| 图标 | 中文 | 英文 | 简述 | +| ------------- | ------------- | ------------- | ------------- | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Method_16x.svg) | 方法 | method, function | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Variable_16x.svg) | 变量 | variable | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Field_16x.svg) | 域 | field | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Class_16x.svg) | 类 | class | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Interface_16x.svg) | 接口 | interface | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Namespace_16x.svg) | 模块 | module | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Property_16x.svg) | 属性 | Properties and Attributes | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/EnumItem_16x.svg) | 枚举 | Values and Enumerations | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Reference_16x.svg) | 引用 | reference | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Keyword_16x.svg) | 关键词 | keyword | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/ColorPalette_16x.svg) | 颜色 | color | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Ruler_16x.svg) | 单位 | unit | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/Snippet_16x.svg) | 代码片段 | (code) snippet | +| ![](https://code.visualstudio.com/assets/docs/editor/intellisense/String_16x.svg) | 词语 | Words | 不归属于上述种类的内容 + +# 详细功能 + +编程语言按字母顺序排列。 + +## JavaScript + +此部分 JS 相关,今后逐步补充其他语言。***由于各测试平台的库有所不同,补全项中的自动导入(auto import)相关部分不在测试范围内。*** + +### 无本插件时 + +使用 VS Code 默认补全配置。在新工作区中拷贝[测试目录](../供测试/js/)进行测试。 + +#### 英文标识符、关键词 + +下面的用例,按照建议弹窗第一项的种类分成几部分。如有更加接近实用的用例,欢迎改进。 + +***可能不需输入所有字符,就会出现在建议弹窗内容第一项,并且之后还有其他项(种类可能各异)。以下无特殊说明也是如此。*** + +| 种类 | 输入 | +| ------------- | ------------- | +方法(语言内置) | isFinite +方法(自定义)| add +变量(语言内置) | console +变量(自定义) | lib_esm +域 | add.arguments +类 | aClass +关键词 | new +代码片段 | log +词语 | zero +模块 |【待添加】 +枚举 |【待添加】 +接口 |【暂未重现】 +属性 |【暂未重现】 +引用 |【暂未重现】 + +#### 中文标识符 + +| 种类 | 输入 | +| ------------- | ------------- | +域 | lib_esm.中文 +变量 | 中文变量 +词语 | lib_esm.中文变量 + +【待补完】 + +### 安装本插件后 + +#### 英文标识符、关键词 + +应与无插件时效果相同。 + +#### 中文标识符 + +中文输入状态下,应与无插件时效果相同。 + +下面为英文输入状态下,不同中文匹配方式。 + +- 全拼 + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +方法 | jf | 加法 +变量 | zwbl | 中文变量 +域 | lib_esm.zw | 中文 +类 | xiaol | 小类 +代码片段 | chux | ChuXianCiShu +词语 | lingd | 零蛋 +关键词 |【无中文关键词】 +模块 |【待添加】 +枚举 |【待添加】 + +- 五笔 + +98全码下,输入“hljw”,出现“战国时代” + +## C++ + +测试时使用[此语言插件](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)。测试源码[在此](../供测试/cpp/main.cpp)。 + +### 无本插件时 + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +方法 | oval.求 | 求面积 +变量 | oval | oval +变量 | 椭 | 椭圆 + +### 安装本插件后 + +无本插件的用例仍可用之外: + +注意:“椭圆”的种类本来是“变量”,现在是“词语” + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +方法 | oval.qiu 或 椭圆.qiu | 补全为(仅支持当前文件中的字段) +***词语*** | tuoyuan | 椭圆 + +## PHP + +测试时使用[此语言插件](https://marketplace.visualstudio.com/items?itemName=ms-python.python)。测试源码[在此](../供测试/斐波那契.py)。 + +### 无本插件时 + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +方法 | join | join +关键词 | echo | echo +变量 | $数列 | $数列 + +### 安装本插件后 + +无本插件的用例仍可用之外: + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +词语 | shulie | $数列 + +## Python + +测试时使用[此语言插件](https://marketplace.visualstudio.com/items?itemName=ms-python.python)。测试源码[在此](../供测试/斐波那契.py)。 + +### 无本插件时 + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +方法 | print | print +关键词 | for | for +变量 | 数 | 数 + +### 安装本插件后 +无本插件的用例仍可用之外: + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +变量 | feibonaqi | 斐波那契 + +## TypeScript + +测试源码[在此](../供测试/加载词典.ts)。 + +### 无本插件时 + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +方法 | print | print +关键词 | function | function +变量 | 词典数据 | 词典数据 + +### 安装本插件后 + +无本插件的用例仍可用之外: + +| 种类 | 输入 | 补全项文本 | +| ------------- | ------------- | ------------- | +变量 | cidianshuju | 词典数据 + +## 编程语言无关 + +### 无语言支持插件时 + +如果并未安装当前源码文件对应的编程语言插件,将按照文本文件处理,支持当前文件中的中文字段的补全。比如在未安装 Kotline 插件时,在[此源码](../供测试/你好.kt) 中输入“ygd”会出现“应该等于”补全。 + +### 第三方 API + +配置项中可以选择百度搜索、谷歌拼音等 API。在输入英文字符时,建议弹窗中会出现对应中文补全项。 + +下面选择百度搜索,以 [JavaScript例程](../供测试/js/) 为例: + +输入“jiafa”,在“加法”方法之外,还有几项拼音相关中文,种类为“词语”,如“假发”。 + +如果访问 API 受阻,会提示用户。 + +### 中英文混合 + +支持中英文混合的标识符补全,在[此源码](../供测试/中英混合.js) 中输入“gettouru”出现“get投入产出比By客户组” + +### 多音字 + +配置项中可以开启多音字。之后在[这里](../供测试/js/index.js) 输入“duozhong”或者“duochong”都会出现“多重笛卡尔积” + +### 代码片段 + +插件中集成了几个编程语言的[代码片段](../片段)。可以通过中、英、拼音等方式触发补全。比如在 JS 源码中输入“array”、“chuxian”或“出”都能触发“出现次数”代码片段。 diff --git "a/\346\226\207\346\241\243/\345\267\262\347\237\245\351\227\256\351\242\230.md" "b/\346\226\207\346\241\243/\345\267\262\347\237\245\351\227\256\351\242\230.md" new file mode 100644 index 0000000000000000000000000000000000000000..aae26568a2112d869ed27b280577c22e15c34f92 --- /dev/null +++ "b/\346\226\207\346\241\243/\345\267\262\347\237\245\351\227\256\351\242\230.md" @@ -0,0 +1,30 @@ + +## JavaScript + +当中文输入状态时,补全项中有时会同时存在带拼音项与不带拼音项,尤其是输入比较慢时更明显。比如输入“中”的过程中,vsc 会在每个字符输入时返回建议(如下)。也许由于每次返回的延时,最后的补全项会有不同。 +``` +"输入词" "z" +日志.js:3 +"返回对象" ["中文变量\tZhongWenBianLiang","加法\tJiaFa","小类\tXiaoLei","零蛋\tLingDan","使用\tShiYong","语法需要\tYuFaXuYao","或者\tHuoZhe","输入\tShuRu"] +日志.js:3 +"================" +日志.js:3 +"输入词" "zhon" +日志.js:3 +"返回对象" ["中文变量\tZhongWenBianLiang","加法\tJiaFa","小类\tXiaoLei","零蛋\tLingDan","使用\tShiYong","语法需要\tYuFaXuYao","或者\tHuoZhe","输入\tShuRu"] +日志.js:3 +"================" +日志.js:3 +"输入词" "zhong" +日志.js:3 +"返回对象" ["中文变量\tZhongWenBianLiang","加法\tJiaFa","小类\tXiaoLei","零蛋\tLingDan","使用\tShiYong","语法需要\tYuFaXuYao","或者\tHuoZhe","输入\tShuRu"] +日志.js:3 +"================" +日志.js:3 +"输入词" "中" +日志.js:3 +"返回对象" ["中文变量\tZhongWenBianLiang","加法\tJiaFa","小类\tXiaoLei","零蛋\tLingDan","中文\tZhongWen","另一个中文\tLingYiGeZhongWen","使用\tShiYong","语法需要\tYuFaXuYao","或者\tHuoZhe","输入\tShuRu"] +``` +## 代码片段 + +输入某些中文,比如 JS 的“出现”时,需要 ctrl+space 触发补全,而且会出现两个同名选项。此时只有选择第一项才有实际代码内容。 diff --git "a/\345\274\200\345\217\221\350\257\264\346\230\216.md" "b/\346\226\207\346\241\243/\345\274\200\345\217\221\350\257\264\346\230\216.md" similarity index 100% rename from "\345\274\200\345\217\221\350\257\264\346\230\216.md" rename to "\346\226\207\346\241\243/\345\274\200\345\217\221\350\257\264\346\230\216.md" diff --git "a/\350\241\245\345\205\250\345\256\236\347\216\260.js" "b/\350\241\245\345\205\250\345\256\236\347\216\260.js" index fa932438dffba16595c1187a19183242a0744b47..32f18d7baa4055c5b5682868f266c1d47d3f4a50 100755 --- "a/\350\241\245\345\205\250\345\256\236\347\216\260.js" +++ "b/\350\241\245\345\205\250\345\256\236\347\216\260.js" @@ -1,44 +1,12 @@ -const vscode = require('vscode') -const bopomofo = require('./bopomofo') -const 五笔 = require('./五笔输入法') -const 谷歌输入法 = require('./lib/谷歌输入法API') -const 百度搜索联想 = require('./lib/百度搜索联想') -var pinyin = require("pinyin") -var 字符串扩展 = require("./lib/字符串扩展") -var { 多重笛卡尔积 } = require("./lib/数组扩展") +var vscode = require('vscode') var R = require('ramda') +var { log } = require('./lib/日志') +var { 包含中文, 查找词组, 是纯字母 } = require('./lib/字符串扩展') +var { 数组去重 } = require('./lib/数组扩展') +var 获得中文字符表示 = require('./lib/获得中文字符表示') +var 谷歌输入法API = require('./lib/谷歌输入法API') +var 百度搜索联想 = require('./lib/百度搜索联想') -function 包含中文(str) { - return /.*[\u4e00-\u9fa5]+.*$/.test(str) -} -var 数组去重 = 数组 => Array.from(new Set(数组)) -function 查找词组(s) { - var wordPattern = /(-?\d*\.\d\w*)|([^\`\~\!\@\^\&\*\(\)\-\#\?\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s?。,、;:?…—·ˉˇ¨“”~〃|《》〔〕(),]+)/g; - return 数组去重(s.match(wordPattern)) -} -function 获得文档内容(document, position) { - var 总行数 = document.lineCount - var 当前行 = position.line - var 文档内容 = "" - for (var i = 0; i < 总行数; i++) { - if (i != 当前行) - 文档内容 += document.lineAt(i).text + "\n"; - } - return 文档内容 -} -function 获得拼音(提示方式, 文本) { - var 拼音 = null - if (提示方式.indexOf("五笔") != -1) { - 拼音 = [五笔.五笔(文本, 提示方式)] - } else { - var 使用多音字 = vscode.workspace.getConfiguration('ChineseInputAssistant').get("InputMethod_polyphone") - 拼音 = pinyin(文本, { heteronym: 使用多音字 == 'yes', style: pinyin.STYLE_NORMAL }) - 拼音 = 拼音.map(a => a.map(a => 字符串扩展.转换为大写(a[0]) + a.substring(1))) - 拼音 = 多重笛卡尔积(拼音).map(a => a.join('')) - if (提示方式 != "全拼") 拼音 = 拼音.map(a => bopomofo.双拼转换(a, 提示方式)) - } - return 拼音 -} function 获得当前输入词() { // 我们需要的是文本被编辑后的情况 而不是编辑前的情况 // 在某些地方调用 会意外的 获得文本被编辑前的情况 @@ -61,97 +29,86 @@ function 获得当前输入词() { }) } -var 上次的补全词 = [] -var provideCompletionItems_上次调用输入词 = undefined +// vscode.executeCompletionItemProvider 会调用 provideCompletionItems 导致无限递归 +// 因为 js 是单线程模型 所以做了一个简单的锁 应该不会有问题 +var 防递归锁 = false async function provideCompletionItems(document, position, token, context) { - var 当前文件类型 = R.last(document.fileName.split('.')) - - var 当前输入词 = await 获得当前输入词() - // console.log('当前输入词', 当前输入词) - - // 防止无限递归 - if (当前输入词 == provideCompletionItems_上次调用输入词) { - // console.log('重复调用') - return [] - } - provideCompletionItems_上次调用输入词 = 当前输入词 - - // 获得配置项 - var 使用输入法 = vscode.workspace.getConfiguration('ChineseInputAssistant').get("InputMethod") - var 提示方式 = vscode.workspace.getConfiguration('中文代码快速补全').get("提示方式") - - var 提示文本们 = [] - - // 获得系统解析出的关键字 - // vscode.executeCompletionItemProvider 会调用provideCompletionItems 所以要防止无限递归 - var 系统解析出的关键字 = await vscode.commands.executeCommand('vscode.executeCompletionItemProvider', document.uri, position) - 提示文本们 = 提示文本们.concat(系统解析出的关键字.items) - - // 对 c/cpp 的特殊处理 - if (当前文件类型 == 'c' || 当前文件类型 == 'cpp') { - // 加入上次的补全词 - 上次的补全词 = 上次的补全词.map(a => a.label).filter(a => a.indexOf('\t') != -1).map(a => a.split('\t')[0]) - 提示文本们 = 提示文本们.concat(上次的补全词.filter(a => !提示文本们.map(b => b.label).includes(a)).map(a => ({ - label: a, - kind: vscode.CompletionItemKind.Text, - }))) - - // 获得当前文档的所有中文 加入候选项 - var 中文词组 = R.compose(R.filter(包含中文), 查找词组)(获得文档内容(document, position)) - 提示文本们 = 提示文本们.concat(中文词组.filter(a => !提示文本们.map(b => b.label).includes(a)).map(a => ({ - label: a, - kind: vscode.CompletionItemKind.Text, - }))) - } - - // 获得输入法提供的关键字 - if (使用输入法 != 'no') { - var func - - if (使用输入法 == 'Google Pinyin') - func = 谷歌输入法 - else if (使用输入法 == 'Baidu Sugrec') - func = 百度搜索联想 - - var 输入法结果 = await func(当前输入词)(5).catch(e => { - console.error('调用输入法api失败:' + e.toString()) - 输入法结果 = [] - }) - 提示文本们 = 提示文本们.concat(输入法结果.map(a => ({ - label: a, - kind: vscode.CompletionItemKind.Text, - }))) - } - - // 将带中文的标签加入拼音返回 - // 不带中文的不需要包括在返回结果里 - // 这个函数只需要返回新增的提示 不需要返回原有的提示 - var 返回对象 = 提示文本们.map(补全对象 => { - var 文本 = 补全对象.label - if (包含中文(文本)) { - return 获得拼音(提示方式, 文本).map(拼音 => { - var r = new vscode.CompletionItem(文本) - r.label = `${文本}\t${拼音}` - r.kind = 补全对象.kind - r.insertText = 补全对象.insertText || 文本 - return r + var 输入词 = await 获得当前输入词() || '' + + if (防递归锁) return [] + 防递归锁 = true + + log('================') + log('输入词', 输入词) + + // var 文件后缀名 = R.last(document.fileName.split('.')) + // log('当前文件后缀名', 文件后缀名) + + var 用户配置 = {} + 用户配置.使用输入法 = vscode.workspace.getConfiguration('ChineseInputAssistant').get("InputMethod") + 用户配置.使用多音字 = vscode.workspace.getConfiguration('ChineseInputAssistant').get("InputMethod_polyphone") + 用户配置.提示方式 = vscode.workspace.getConfiguration('中文代码快速补全').get("提示方式") + // log('用户配置', 用户配置) + + var 返回对象 = [] + + var 完成项提供程序 = await vscode.commands.executeCommand('vscode.executeCompletionItemProvider', document.uri, position) + 完成项提供程序 = 完成项提供程序.items + 返回对象 = 返回对象.concat(完成项提供程序) + // log('完成项提供程序', 完成项提供程序.map(a => a.label)) + + 防递归锁 = false + + // 这个好像很卡 + // var 文档符号提供程序 = await vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', document.uri) + // 文档符号提供程序 = 文档符号提供程序.map(a => new vscode.CompletionItem(a.name, a.kind)) + // 返回对象 = 返回对象.concat(文档符号提供程序) + // log('文档符号提供程序', 文档符号提供程序.map(a => a.label)) + + var 文档符号 = R.compose(R.filter(包含中文), 查找词组)(document.getText()) + 文档符号 = 文档符号.map(a => new vscode.CompletionItem(a, vscode.CompletionItemKind.Text)) + 返回对象 = 返回对象.concat(文档符号) + // log('文档符号', 文档符号.map(a => a.label)) + + if (用户配置.使用输入法 != 'no') { + // 如果我想分别输入一个词组 例如 "多重笛卡尔积" + // 我的输入顺序是 先输入 "多重" 再输入 "笛卡尔积" 这是一个组词 而不是一次性打出来 + // 当我输入到 "多重d"的时候 `输入词`这个变量是"多重d" 如果直接拿这个词去调用输入法 很难得到正确的结果 + // 我们期待的应该是 此时 使用"d"去调用输入法 + // 但这样也是不可行的 如果我拿"d"去调用输入法 确实可以得到正确的结果 但此时 得到的结果 并不是以"多重"开头的 便不会弹出提示框 + // 因此 这里的方案是 同时获得前缀(不带字母的)的和纯字母输入词 用纯字母输入词调用输入法 再在结果前面补上前缀 + // 注意 这个策略在一些情况下会失效 例如 在汉字中间输入时 + var 前缀 = 输入词.split('').filter(a => !是纯字母(a)).join('') + var 纯字母输入词 = 输入词.split('').filter(a => 是纯字母(a)).join('') + var 输入法提供的词 = [] + var 输入法 = null + if (用户配置.使用输入法 == 'Google Pinyin' && 纯字母输入词 != '' && 纯字母输入词 != null) { + 输入法 = 谷歌输入法API + } else if (用户配置.使用输入法 == 'Baidu Sugrec' && 纯字母输入词 != '' && 纯字母输入词 != null) { + 输入法 = 百度搜索联想 + } + if (输入法 != null) { + 输入法提供的词 = await 输入法(纯字母输入词).catch(e => { + console.error(e) + vscode.window.showInformationMessage(`调用输入法接口出错:` + e) }) + 输入法提供的词 = 输入法提供的词.map(a => 前缀 + a).map(a => new vscode.CompletionItem(a, vscode.CompletionItemKind.Text)) + 返回对象 = 返回对象.concat(输入法提供的词) } + } - // cpp 插件很奇怪 必须要原样返回 - if (当前文件类型 == 'c' || 当前文件类型 == 'cpp') - return [补全对象] - - return [] - }).flat() + 返回对象 = 数组去重((a, b) => a.label == b.label, 返回对象) + 返回对象 = 返回对象.filter(a => 包含中文(a.label)).filter(a => a.label != 输入词) + 返回对象 = 返回对象.map(a => R.set(R.lensProp('insertText'), a.label, a)) - // 对 c/cpp 的特殊处理 - if (当前文件类型 == 'c' || 当前文件类型 == 'cpp') { - 上次的补全词 = 返回对象 - } + 返回对象 = 返回对象.map(a => R.set(R.lensProp('label'), `${a.label}\t${获得中文字符表示({ + 表示方法: 用户配置.提示方式, + 文本: a.label, + 选项: { 使用多音字: 用户配置.使用多音字 } + })}`, a)) - // console.log(返回对象.map(a => a.label).join(',')) - return 返回对象 + log('返回对象', 返回对象.map(a => a.label)) + return new vscode.CompletionList(返回对象, true) } function resolveCompletionItem(item, token) { @@ -159,10 +116,11 @@ function resolveCompletionItem(item, token) { } module.exports = function (context) { - // 注册触发补全功能时调用的函数 - context.subscriptions.push(vscode.languages.registerCompletionItemProvider({ scheme: 'file', language: '*' }, { + context.subscriptions.push(vscode.languages.registerCompletionItemProvider({ + scheme: 'file', + language: '*' + }, { provideCompletionItems, resolveCompletionItem - }, '.', '$', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')) + }, '.', '$')) } -