Add GCC Commands Options index

Update version to v0.4.0
Remove `/jcr update`
Add `/jcr help`
This commit is contained in:
2023-04-22 17:03:24 +08:00
parent d0d4fdca32
commit 6a21e074c7
6 changed files with 3555 additions and 84 deletions

View File

@ -1,20 +1,22 @@
# mirai-console-jcr-plugin
## J Cpp Reference Plugin
在QQ群内搜索 [CppReference](https://en.cppreference.com/w/) 和 [Qt](https://doc.qt.io/) 的文档
在QQ群内搜索 `C/C++` 文档的 [mirai](https://github.com/mamoe/mirai) 插件
# 用法
```shell
# 消息检测
c <keyword> # 搜索C文档
cpp <keyword> # 搜索CPP文档
qt <keyword> # 搜索Qt文档
c <keyword> # 查询C标准库
cpp <keyword> # 查询C++标准库
qt <keyword> # 查询Qt类库
gcc <keyword> # 查询GCC命令行选项
# 控制台命令
/jcr update # 更新CPP索引
/jcr help # 获取帮助
```
# 索引来源
- c 索引来自官网离线文档,手动解析生成
- cpp 索引来自 https://github.com/Guyutongxue/cppreference-index 感谢 @Guyutongxue
- qt 索引来自 https://github.com/therecipe/qt ,经过二次处理手动解析生成
- qt 索引来自 Qt 官网,版本 `Qt 5.13.0`
- gcc 命令行选项索引来自[GNU](https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Option-Index.html)官网,版本 `GCC 12.2.0`

View File

@ -3,11 +3,11 @@ plugins {
kotlin("jvm") version kotlinVersion
kotlin("plugin.serialization") version kotlinVersion
id("net.mamoe.mirai-console") version "2.12.2"
id("net.mamoe.mirai-console") version "2.14.0"
}
group = "top.jie65535"
version = "0.3.0"
version = "0.4.0"
repositories {
maven("https://maven.aliyun.com/repository/public") // 阿里云国内代理仓库

View File

@ -1,10 +1,7 @@
package top.jie65535.jcr
import kotlinx.coroutines.runInterruptible
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import okhttp3.Request
@OptIn(kotlinx.serialization.ExperimentalSerializationApi::class)
object Data {
@ -20,6 +17,7 @@ object Data {
/**
* 初始化数据
* 更新索引https://cdn.jsdelivr.net/npm/@gytx/cppreference-index/dist/generated.json
*/
fun initData() {
val linkMap = JCppReferencePlugin.resolveDataFile("linkmap.json")
@ -36,31 +34,6 @@ object Data {
}
}
private val httpClient by lazy { OkHttpClient() }
/**
* 更新数据
*/
suspend fun updateData() {
val call = httpClient.newCall(Request.Builder()
.url("https://cdn.jsdelivr.net/npm/@gytx/cppreference-index/dist/generated.json")
.build())
JCppReferencePlugin.logger.info("正在下载索引")
runInterruptible {
val response = call.execute()
if (response.isSuccessful) {
val json = response.body!!.string()
indexes = Json.decodeFromString(json)
// 保存到文件
JCppReferencePlugin.resolveDataFile("linkmap.json")
.writeText(json)
JCppReferencePlugin.logger.info("索引更新完成")
} else {
JCppReferencePlugin.logger.error("下载失败 HTTP Code: ${response.code}")
}
}
}
/**
* 获取索引
*/

View File

@ -4,6 +4,7 @@ import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
import net.mamoe.mirai.event.GlobalEventChannel
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.message.data.MessageSource.Key.quote
import net.mamoe.mirai.utils.info
@ -14,20 +15,40 @@ object JCppReferencePlugin : KotlinPlugin(
JvmPluginDescription(
id = "top.jie65535.mirai-console-jcr-plugin",
name = "J Cpp Reference Plugin",
version = "0.3.0"
version = "0.4.0"
) {
author("jie65535")
info("C++ 参考搜索插件")
info("C/C++ 参考搜索插件")
}
) {
private const val cppreferencePrefix = "https://zh.cppreference.com/w/"
private const val qtDocPrefix = "https://doc.qt.io/qt-5/"
private const val gccDocPrefix = "https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/"
private fun loadMap(path: String): Map<String, String> {
/**
* C索引
*/
private val indexC by lazy { loadMap("/devhelp-index-c.txt") }
/**
* Qt文档索引::分割
*/
private val indexQt by lazy {
val map = loadMap("/qt-5.13.0.txt")
splitKeys(map as MutableMap<String, String>)
map
}
/**
* GCC编译选项索引不能忽略大小写
*/
private val indexGcc by lazy { loadMap("/gcc-12-opt-index.txt", false) }
private fun loadMap(path: String, ignoreCase: Boolean = true): Map<String, String> {
val map = mutableMapOf<String, String>()
val stream = this::class.java.getResourceAsStream(path)
if (stream == null) {
logger.error("资源文件为空")
logger.error("无法找到指定资源:$path")
} else {
stream.use {
val br = BufferedReader(InputStreamReader(stream))
@ -38,17 +59,30 @@ object JCppReferencePlugin : KotlinPlugin(
val key = line.substring(0, s)
val url = line.substring(s+1)
map.putIfAbsent(key, url)
val lowerKey = key.lowercase()
map.putIfAbsent(lowerKey, url)
}
}
}
splitKeys(map)
// 如果忽略大小写则将key的小写形式也加入索引
if (ignoreCase) {
// 使用临时的map来存储小写版本
val lowerMap = mutableMapOf<String, String>()
for ((key, value) in map.entries) {
lowerMap.putIfAbsent(key.lowercase(), value)
}
// 插入回返回索引
for ((key, value) in lowerMap.entries) {
map.putIfAbsent(key.lowercase(), value)
}
}
}
logger.info("\"$path\" ${map.size} keywords loaded")
return map
}
/**
* 按照 `::` 分割关键字
*/
private fun splitKeys(map: MutableMap<String, String>) {
val subMap = mutableMapOf<String, String>()
for (item in map) {
@ -68,9 +102,6 @@ object JCppReferencePlugin : KotlinPlugin(
}
}
private val indexC by lazy { loadMap("/devhelp-index-c.txt") }
private val indexQt by lazy { loadMap("/qt-5.13.0.txt") }
override fun onEnable() {
logger.info { "Plugin loaded" }
PluginCommands.register()
@ -78,43 +109,91 @@ object JCppReferencePlugin : KotlinPlugin(
val eventChannel = GlobalEventChannel.parentScope(this)
eventChannel.subscribeMessages {
startsWith("c ") { checkC(it) }
startsWith("C ") { checkC(it) }
startsWith("cpp ") { checkCpp(it) }
startsWith("CPP ") { checkCpp(it) }
startsWith("c++ ") { checkCpp(it) }
startsWith("C++ ") { checkCpp(it) }
startsWith("qt ") { checkQt(it) }
startsWith("Qt ") { checkQt(it) }
startsWith("QT ") { checkQt(it) }
startsWith("gcc ") { checkGcc(it) }
startsWith("GCC ") { checkGcc(it) }
}
}
startsWith("c ") { keyword ->
if (keyword.isEmpty()) return@startsWith
logger.info("check c \"$keyword\"")
var cLink = indexC[keyword]
if (cLink != null) {
subject.sendMessage(message.quote() + cppreferencePrefix + cLink)
} else {
cLink = indexC[keyword.lowercase()]
if (cLink != null) {
subject.sendMessage(message.quote() + cppreferencePrefix + cLink)
}
}
}
/**
* 查找C文档
*/
private suspend fun MessageEvent.checkC(keyword: String) {
if (keyword.isEmpty()) return
logger.info("check c \"$keyword\"")
findAndReply(indexC, keyword, cppreferencePrefix)
}
startsWith("cpp ") { keyword ->
if (keyword.isEmpty()) return@startsWith
logger.info("check cpp \"$keyword\"")
val index = Data.getIndex(keyword)
if (index != null) {
subject.sendMessage(message.quote() + cppreferencePrefix + index.link)
}
}
/**
* 查找C++文档
*/
private suspend fun MessageEvent.checkCpp(keyword: String) {
if (keyword.isEmpty()) return
logger.info("check cpp \"$keyword\"")
val index = Data.getIndex(keyword)
if (index != null) {
subject.sendMessage(message.quote() + cppreferencePrefix + index.link)
}
}
startsWith("qt ") { keyword ->
if (keyword.isEmpty()) return@startsWith
logger.info("check qt \"$keyword\"")
var qtLink = indexQt[keyword]
if (qtLink != null) {
subject.sendMessage(message.quote() + qtDocPrefix + qtLink)
} else {
qtLink = indexQt[keyword.lowercase()]
if (qtLink != null) {
subject.sendMessage(message.quote() + qtDocPrefix + qtLink)
}
}
}
/**
* 查找Qt文档
*/
private suspend fun MessageEvent.checkQt(keyword: String) {
if (keyword.isEmpty()) return
logger.info("check qt \"$keyword\"")
findAndReply(indexQt, keyword, qtDocPrefix)
}
/**
* 查找GCC命令行文档
*/
private suspend fun MessageEvent.checkGcc(keyword: String) {
if (keyword.isEmpty()) return
logger.info("check gcc \"$keyword\"")
if (!findAndReply(indexGcc, keyword, gccDocPrefix, false) && keyword.startsWith('-')) {
findAndReply(indexGcc, keyword.substring(1), gccDocPrefix, false)
}
}
/**
* 从索引中查找并拼接前缀回复发送者
* @param index 索引
* @param keyword 关键字
* @param prefix 前缀
* @param ignoreCase 忽略大小写 默认true
* @return 返回是否回复
*/
private suspend fun MessageEvent.findAndReply(index: Map<String, String>, keyword: String, prefix: String, ignoreCase: Boolean = true): Boolean {
if (keyword.isEmpty()) return false
val url = find(index, keyword, prefix) ?: if (ignoreCase) find(index, keyword.lowercase(), prefix) else null
return if (url != null) {
subject.sendMessage(message.quote() + url)
true
} else false
}
/**
* 从索引中查找并拼接前缀返回
* @param index 索引
* @param keyword 关键字
* @param prefix 前缀
* @return 返回查找结果未找到返回null
*/
private fun find(index: Map<String, String>, keyword: String, prefix: String): String? {
val value = index[keyword]
return if (value != null) {
prefix + value
} else {
null
}
}
}

View File

@ -8,9 +8,13 @@ object PluginCommands : CompositeCommand(
description = "J CppReference Commands"
) {
@SubCommand
@Description("更新索引")
suspend fun CommandSender.update() {
Data.updateData()
sendMessage("OK")
@Description("查询帮助")
suspend fun CommandSender.help() {
sendMessage("""
c <keyword> # 查询C标准库
cpp <keyword> # 查询C++标准库
qt <keyword> # 查询Qt类库
gcc <keyword> # 查询GCC命令行选项
""".trimIndent())
}
}

File diff suppressed because it is too large Load Diff