为Godot脚本文件生成Markdown的静态函数库MDCreater

MDCreater.gd

基本信息

脚本信息

项目 信息
文件名 MDCreater.gd
is_tool
extend -
class_name -

文件信息

项目 信息
项目名称 myAdd插件v3.0
文件路径 res://addons/myAdd/lib/MDCreater.gd
绝对路径 E:/【Godot-项目】/myAdd插件v3.0/addons/myAdd/lib/MDCreater.gd

其他信息

项目 信息
作者 @巽星石
备注 源码与本文档一起开放,任何人任何使用方式都可以。
一切在此基础上的修改也好,开源也好,闭源也好,商用都可以,也无需著名原作者。

文档信息

项目 信息
文档创建时间 2022-09-24 23:13:18

概述

这是一个基于Godot3.5的GDScript编写的脚本快速生成Markdown的静态函数库。

其中主要包含Markdown语法生成相关的函数以及生成和保存脚本文档的函数。

用途及用法

1.用于快速生成Markdown文档的源码

你可以使用其中的Markdown语法生成相关的函数来快速生成Markdown文档的源码。

例如像下面这样:

code_editor.text += md.TOC()
code_editor.text += md.quote("这是一个单行引用")
code_editor.text += md.quote("这是一个单行引用2\n22")
code_editor.text += md.H(1,"MDCreater测试")
code_editor.text += md.H(2,"代码块")
code_editor.text += md.Code_Block(self.get_script().source_code,"gdscript") # 显示源码自身
code_editor.text += md.HR()
code_editor.text += md.H(2,"表格")
code_editor.text += md.TH(["属性","值类型","默认值","描述"])
code_editor.text += md.TR(["name","Sting","\"\"","名称"])
code_editor.text += md.TR(["age","int","0","年龄"])
code_editor.text += md.TR(["sex","int","0","性别"])
code_editor.text += md.HR()
code_editor.text += md.H(2,"超链接")
code_editor.text += md.link("https://www.baidu.com/","摆烂的百度")
code_editor.text += md.H(2,"图片")
code_editor.text += md.img("res://360截图20220919201410658.png","项目封面图")
code_editor.text += md.H(2,"列表")
code_editor.text += md.P("列表是用于展示并列信息的。\n分为有序列表和无序列表。")
code_editor.text += md.H(3,"有序列表")
code_editor.text += md.OL(
    [
        "有序列表是带有编号的列表",
        "通常用于表示步骤等"
    ]
)
code_editor.text += md.H(3,"无序列表")
code_editor.text += md.UL(
    [
        "无序列表是不带编号的列表",
        "通常用于纯粹并列的条目和内容。"
    ]
)

上面的代码会获得符合Markdown语法的字符串:

@[toc]
> 这是一个单行引用
> 这是一个单行引用2
> 22
# MDCreater测试
## 代码块
```gdscript
extends Control

var md = MDCreater.new()
onready var code_editor = $codeEditor

func _ready():
#	md.GDscript_MD(get_script(),"res://22.md")
#	md.GDscript_MD_by_path("res://addons/myAdd/lib/MDCreater.gd","res://MDCreater.md")
#	md.GDscript_MD_by_path("res://addons/myTreeAdd/lib/GDEditor.gd","res://GDEditor.md")
	code_editor.text += md.TOC()
	code_editor.text += md.quote("这是一个单行引用")
	code_editor.text += md.quote("这是一个单行引用2\n22")
	code_editor.text += md.H(1,"MDCreater测试")
	code_editor.text += md.H(2,"代码块")
	code_editor.text += md.Code_Block(self.get_script().source_code,"gdscript") # 显示源码自身
	code_editor.text += md.HR()
	code_editor.text += md.H(2,"表格")
	code_editor.text += md.TH(["属性","值类型","默认值","描述"])
	code_editor.text += md.TR(["name","Sting","\"\"","名称"])
	code_editor.text += md.TR(["age","int","0","年龄"])
	code_editor.text += md.TR(["sex","int","0","性别"])
	code_editor.text += md.HR()
	code_editor.text += md.H(2,"超链接")
	code_editor.text += md.link("https://www.baidu.com/","摆烂的百度")
	code_editor.text += md.H(2,"图片")
	code_editor.text += md.img("res://360截图20220919201410658.png","项目封面图")
	code_editor.text += md.H(2,"列表")
	code_editor.text += md.P("列表是用于展示并列信息的。\n分为有序列表和无序列表。")
	code_editor.text += md.H(3,"有序列表")
	code_editor.text += md.OL(
		[
			"有序列表是带有编号的列表",
			"通常用于表示步骤等"
		]
	)
	code_editor.text += md.H(3,"无序列表")
	code_editor.text += md.UL(
		[
			"无序列表是不带编号的列表",
			"通常用于纯粹并列的条目和内容。"
		]
	)
	pass 


```
------
## 表格
| 属性 | 值类型 | 默认值 | 描述 | 
| --- |--- |--- |--- |
| name |Sting |"" |名称 |
| age |int |0 |年龄 |
| sex |int |0 |性别 |
------
## 超链接
[摆烂的百度](https://www.baidu.com/)
## 图片
![项目封面图](res://360截图20220919201410658.png)
## 列表

列表是用于展示并列信息的。
分为有序列表和无序列表。
### 有序列表
0. 有序列表是带有编号的列表
1. 通常用于表示步骤等
### 无序列表
- 无序列表是不带编号的列表
- 通常用于纯粹并列的条目和内容。

2.用于生成GDScript脚本文件的文档

就像你看到的这个文档一样,MDCreater可以使用GDscript_MD_by_path()方法生成GDScript脚本文件的Markdown文档。当然只是一个框架,方便继续修改和填充。

var md = MDCreater.new() # 创建MDCreater实例
# 调用GDscript_MD_by_path()方法
# 传入要生成文档的脚本路径,以及生成的文档的保存路径
md.GDscript_MD_by_path("res://addons/myAdd/lib/MDCreater.gd","res://MDCreater.md")

你也可以使用GDscript_MD()方法,传入的第一个参数变为一个gdscript对象。

var md = MDCreater.new() # 创建MDCreater实例
md.GDscript_MD_by_path(get_script(),"res://22.md")

上面的代码如果用在某个打开的场景的脚本中,将会直接生成该这个脚本的Markdown文档。

信号

信号 描述
click()
dbl_click(name,button)

枚举

aa

可选值 描述
CC
BB
AA

aa2

可选值 描述
AA

属性

导出变量

变量 值类型 默认值 描述
export(String,“12”,“34”) var title String “” 测试用,可选值:“12”,“34”
export var title2 =“12” String “12” 测试用
export var title3 :=“1212” String “1212” 测试用

普通全局变量

变量 值类型 默认值 描述
var host 未知 null 测试用
var db:String String “” 测试用
var face = Texture.new() Texture 一个新的Texture实例 测试用

onready变量

变量 值类型 默认值 描述
onready var mm 未知 null 测试用

常量

常量 值类型 描述
PI2 = 123 int 123 测试用
tscn = preload(“res://属性列表测试.tscn”) PackedScene preload(“res://属性列表测试.tscn”) 测试用

方法

H(level:int,title:String) -> String

生成Markdown的H1-H6标题,level表示标题层级,title即标题文本。

H(1,"一级标题") //生成“# 一级标题”
H(2,"二级标题") //生成“## 二级标题”
H(3,"三级标题") //生成“### 三级标题”
H(4,"四级标题") //生成“#### 四级标题”
H(5,"五级标题") //生成“##### 五级标题”
H(6,"六级标题") //生成“###### 六级标题”

P(content:String) -> String

生成Markdown的段落。

P("这是一个段落") //生成“\n这是一个段落\n”

可以看到其本质是在原字符串的前后加上了"\n",也就是换行。

quote(content:String) -> String

生成Markdown的引用。

quote("这是一段引用")

生成如下Markdown语法:

> 这是一段引用\n

Code_Block(code:String,languege:String = “”) -> String

生成Markdown的代码块。

Code_Block("export var a:int = 12","GDScript")

生成如下Markdown语法:

```GDScript
export var a:int = 12
```

Code_Inline(code:String) -> String

生成行内代码。

OL(str_list:PoolStringArray) -> String

生成有序列表。

OL([
	"item1",
	"item2",
	"item3",
])

生成如下Markdown语法:

1. item1
2. item2
3. item3

UL(str_list:PoolStringArray) -> String

生成无序列表。

UL([
	"item1",
	"item2",
	"item3",
])

生成如下Markdown语法:

- item1
- item2
- item3

HR() -> String

生成水平分割线。生成如下Markdown语法:

------

TOC() -> String

生成内容目录。生成如下Markdown语法:

@[toc]

link(url:String,title:String="") -> String

生成超链接。无果没有设定title参数,也就是链接的标题,会直接返回url本身。

如果设定了title参数,则生成如下Markdown语法:

[title](url)

img(src:String,title:String="") -> String

生成插入图片的MD代码。生成如下Markdown语法:

![title](src)

TH(fields:PoolStringArray) -> String

遍历fields参数所指定的字段列表生成表头。

TH(["属性","默认值","描述"])

生成如下Markdown语法:

| 属性 | 默认值 | 描述 |
| --- | --- | --- |

也就是生成如下的表头:

属性 默认值 描述

TR(vals:PoolStringArray) -> String

根据vals参数给定的值,生成表格的一行。通常需要与TH()函数一块使用。先用TH()函数生成表头和字段,再用TR()函数生成行和字段的值。

注意:请尽量与TH()函数所指定的字段数目和含义保持一致。

TH(["属性","值","描述"])
TR(["name","张三","姓名"])
TR(["sex","0","性别"])
TR(["age","25","年龄"])

生成如下Markdown语法:

| 属性 | 值 | 描述 |
| --- | --- | --- |
| name | 张三 | 姓名 |
| sex | 0 | 性别 |
| age | 25 | 年龄 |

也就是生成如下的表格:

属性 描述
name 张三 姓名
sex 0 性别
age 25 年龄

GDscript_MD_by_path(script_path:String,md_save_path:String)

生成由script_path指定的GDScript脚本文件的Markdown框架文档。

var md = MDCreater.new() # 创建MDCreater实例
md.GDscript_MD_by_path("res://addons/myAdd/lib/MDCreater.gd",res://MDCreater.md")

上面的代码,将会为"res://addons/myAdd/lib/MDCreater.gd"指向的GDScript脚本文件创建Markdown框架文档,保存路径为"res://MDCreater.md"。

注意:其内部是调用GDscript_MD()方法。

GDscript_MD(script:Script,md_save_path:String)

生成由script指定的GDScript脚本对象的Markdown框架文档。

var md = MDCreater.new() # 创建MDCreater实例
md.GDscript_MD_by_path(get_script(),"res://22.md")

上面的代码,会为当前的脚本创建Markdown框架文档,保存为"res://22.md"。

has_class_name(script:Script) -> bool

判断脚本是否为”类脚本“,也就是有没有定义class_name。如果定义了class_name,则返回true。

script_class_name(script:Script) -> String

如果脚本是否为”类脚本“,也就是有定义了class_name。则返回其定义的class_name。

has_extend_name(script:Script) -> bool

判断脚本是否有extends关键字,如果有,返回true。

extend_class_name(script:Script) -> String

如果脚本有extends关键字,返回其extends的类型。

get_script_method_list(script:Script) -> PoolStringArray

返回脚本的方法列表 - 只包含源码内部自己定义的,不包含继承来的。

get_script_enum_list(script:Script) -> Array

返回脚本的枚举列表 - 只包含源码内部自己定义的,不包含继承来的。

返回如下形式:

[[name,vals],[name,vals],[name,vals]...]

其中name是枚举的名称,vals是值列表。

get_script_property_list(script:Script) -> Array

返回脚本的变量列表 - 只包含源码内部自己定义的,不包含继承来的

返回形式如下:

[[导出变量数组],[onready变量数组],[普通全局变量数组]]

get_script_const_list(script:Script) -> PoolStringArray

返回脚本的常量列表 - 只包含源码内部自己定义的,不包含继承来的。

get_script_signal_list(script:Script) -> PoolStringArray

返回脚本的信号列表 - 只包含源码内部自己定义的,不包含继承来的。

saveString(path:String,content:String) -> void

保存字符串到指定路径的文件。函数库内部快速保存纯文本文件的快捷函数。

get_date_time() -> String

返回当前日期时间。函数库内部快速获取当前日期时间的快捷函数。

源代码

这里是完整源代码:

# =======================================
# MDCreater - MarkDown快速生成 - 函数库
# 202292412:34:33
# @巽星石
# 说明:本函数库基于Typora编辑器所支持的语法进行创建
# =======================================

class_name MDCreater


# H1-H6
static func H(level:int,title:String) -> String:
	level = clamp(level,1,6)
	var h_str = "#".repeat(level) + " " + title + "\n"
	return h_str

# 普通段落
static func P(content:String) -> String:
	return "\n" + content + "\n"
	
# quote - 引用
static func quote(content:String) -> String:
	var return_str = ""
	if "\n" in content: # 如果传入的内容为多行文本
		var quts = content.split("\n",false)
		return_str = "> %s\n".repeat(quts.size())
		return_str = return_str % quts as Array
	else:
		return_str = "> %s\n" % content
	return return_str

# 代码块
static func Code_Block(code:String,languege:String = "") -> String:
	return "```%s\n%s```\n" % [languege,code]
	
# 行内代码
static func Code_Inline(code:String) -> String:
	return "`%s`" % [code]
	
# OL - 有序列表
static func OL(str_list:PoolStringArray) -> String:
	var return_str =""
	for i in str_list.size():
		 return_str += "%s. %s\n" % [str(i),str_list[i]]
	return  return_str

# UL - 无序列表
static func UL(str_list:PoolStringArray) -> String:
	var return_str =""
	for mstr in str_list:
		 return_str += "- %s\n" % mstr
	return  return_str

# HR - 水平分隔线
static func HR() -> String:
	return "-".repeat(6) + "\n"
	
# TOC - 内容目录
static func TOC() -> String:
	return "[TOC]\n"



# 超链接
static func link(url:String,title:String="") -> String:
	var return_str =""
	if title == "":
		return_str = url
	else:
		return_str = "[%s](%s)\n" % [title,url]	
	return return_str

# 图片
static func img(src:String,title:String="") -> String:
	return "![%s](%s)\n" % [title,src]
	
# 表格 - 表头
static func TH(fields:PoolStringArray) -> String:
	var th = "| " + "%s | ".repeat(fields.size()) + "\n"
	th = th  % fields as Array
	th += "| " + "--- |".repeat(fields.size()) + "\n"
	return th
	
# 表格 - 一行
static func TR(vals:PoolStringArray) -> String:
	var tr = "| " + "%s |".repeat(vals.size()) + "\n"
	tr = tr % vals as Array
	return tr


# ===============GDScript脚本生成Markdown =====================

# 传入路径
static func GDscript_MD_by_path(script_path:String,md_save_path:String):
	var script = load(script_path)
	GDscript_MD(script,md_save_path)

# 生成一个GDscript的基础结构的Markdown文档
static func GDscript_MD(script:Script,md_save_path:String):
	var md_str = ""
	md_str += TOC()
	# 当前时间
	var now_date_time = get_date_time()
	# 资源信息
	var project_name = ProjectSettings.get_setting("application/config/name") # 项目名称
	var resource_path = script.resource_path # 资源路径
	var resource_name = resource_path.get_file() # 脚本的文件名
	var source_code = script.source_code  # 源代码
	# tool
	var is_tool = script.is_tool() # 是否为工具脚本
	# 继承
	var has_extend = has_extend_name(script) # 是否有继承的父类型
	var extend_name = extend_class_name(script) # 脚本的类名
	# 自定义类名
	var is_class = has_class_name(script) # 是否为类脚本
	var script_class_name = script_class_name(script) # 脚本的类名
	md_str += H(1,"%s" % resource_name)
	md_str += H(2,"基本信息")
	# 脚本信息
	md_str += H(3,"脚本信息")
	md_str += TH(["项目","信息"])
	md_str += TR(["文件名",resource_name])
	md_str += TR(["is_tool",("是" if is_tool else "否")])
	md_str += TR(["extend",(extend_name if extend_name else "-")])
	md_str += TR(["class_name",(script_class_name if script_class_name else "-")])
	# 文件信息
	md_str += H(3,"文件信息")
	md_str += TH(["项目","信息"])
	md_str += TR(["项目名称",project_name])
	md_str += TR(["文件路径",resource_path])
	md_str += TR(["绝对路径",ProjectSettings.globalize_path(resource_path)])
	# 其他信息
	md_str += H(3,"其他信息")
	md_str += TH(["项目","信息"])
	md_str += TR(["作者",""])
	md_str += TR(["备注",""])
	# 文档信息
	md_str += H(3,"文档信息")
	md_str += TH(["项目","信息"])
	md_str += TR(["文档创建时间",now_date_time])
	md_str += H(2,"概述")
	md_str += P("这里写概述")
	# 信号
	var signal_names = get_script_signal_list(script)
	if signal_names.size() > 0:
		md_str += H(2,"信号")
		md_str += TH(["信号","描述"])
		for signel in signal_names:
			md_str += TR([signel,""])
			
	# 枚举
	# enum_names返回值形式如下:
	# [[name,vals],[name,vals],[name,vals]...]
	# 其中name是枚举的名称,vals是值列表
	var enum_names = get_script_enum_list(script) # 所有脚本内部方法名
	if enum_names.size() > 0:
		md_str += H(2,"枚举")
		for enu in enum_names:
			md_str += H(3,enu[0])
			md_str += TH(["可选值","描述"])
			var vals = enu[1].split(",")
			for val in vals:
				md_str += TR([val,""])
	
	# 变量
	# 返回形式如下:
	# [[导出变量数组],[onready变量数组],[普通全局变量数组]]
	var var_names = get_script_property_list(script)
	if var_names.size() > 0:
		md_str += H(2,"属性")
		# 导出变量
		if var_names[0].size()>0:
			md_str += H(3,"导出变量")
			md_str += TH(["变量","值类型","默认值","描述"])
			for ver in var_names[0]:
				if ver.begins_with("export"):
					md_str += TR([ver,"","",""])
		# 全局变量
		if var_names[2].size()>0:
			md_str += H(3,"普通全局变量")
			md_str += TH(["变量","值类型","默认值","描述"])
			for ver in var_names[2]:
				if ver.begins_with("var"):
					md_str += TR([ver,"","",""])
		# onready变量
		if var_names[1].size()>0:
			md_str += H(3,"onready变量")
			md_str += TH(["变量","值类型","默认值","描述"])
			for ver in var_names[1]:
				if ver.begins_with("onready"):
					md_str += TR([ver,"","",""])
	# 常量
	var const_names = get_script_const_list(script)
	if const_names.size() > 0:
		md_str += H(2,"常量")
		md_str += TH(["常量","值类型","值","描述"])
		for cst in const_names:
			md_str += TR([cst,"","",""])
	
	# 方法
	var func_names = get_script_method_list(script) # 所有脚本内部方法名
	md_str += H(2,"方法")
	for fuc in func_names:
		md_str += H(3,fuc)
		md_str += P("这里是方法的描述。")
	md_str += H(2,"源代码")
	md_str += P("这里是完整源代码:")
	md_str += Code_Block(source_code,"swift")
	saveString(md_save_path,md_str)
	

# 是否为类
static func has_class_name(script:Script) -> bool:
	var has = false
	var source_code = script.source_code  # 完整 - 源代码
	var regex = RegEx.new()
	regex.compile("class_name .*")
	var result = regex.search(source_code)
	if result:
		has = false
	return has

# 如果为类脚本,返回类名
static func script_class_name(script:Script) -> String:
	var c_name
	var source_code = script.source_code  # 完整 - 源代码
	var regex = RegEx.new()
	regex.compile("class_name (.*)")
	var result = regex.search(source_code)
	if result:
		result.get_string(1)
	return c_name


# 是否有继承
static func has_extend_name(script:Script) -> bool:
	var source_code = script.source_code  # 完整 - 源代码
	var regex = RegEx.new()
	regex.compile("\"extends (.*)\"|extends (.*)")
	var result = regex.search(source_code)
	return true if result.get_string(2) else false


# 如果有继承类型,返回继承名
static func extend_class_name(script:Script) -> String:
	var source_code = script.source_code  # 完整 - 源代码
	var regex = RegEx.new()
	regex.compile("\"extends (.*)\"|extends (.*)")
	var result = regex.search(source_code)
	return result.get_string(2)

# 返回脚本的方法列表 - 只包含源码内部自己定义的,不包含继承来的
static func get_script_method_list(script:Script) -> PoolStringArray:
	var source_code = script.source_code  # 源代码
	var regex = RegEx.new()
	regex.compile("static func (.*):|func (.*):")
	var results = regex.search_all(source_code)
	var func_names:PoolStringArray = []
	for result in results:
		func_names.append(result.get_string(1))
		if result.get_string(2) !="":
			func_names.append(result.get_string(2))
	return func_names

# 返回脚本的枚举列表 - 只包含源码内部自己定义的,不包含继承来的
# 返回如下形式:
# [[name,vals],[name,vals],[name,vals]...]
# 其中name是枚举的名称,vals是值列表
static func get_script_enum_list(script:Script) -> Array:
	var source_code = script.source_code  # 源代码
	var regex = RegEx.new()
	regex.compile("enum (.*){(.*)}|enum (.*){\\n*(.*\\n)*}")
	var results = regex.search_all(source_code)
	var enum_names:Array = []
	for result in results:
		# [name,vals]
		if result.get_string(1) != "":
			var enum_info = [result.get_string(1),result.get_string(2)]
			enum_names.append(enum_info)
		if result.get_string(3) != "":
			var enum_info = [result.get_string(3),result.get_string(4).replace("\n","").replace("\t","")]
			enum_names.append(enum_info)
	return enum_names

# 返回脚本的变量列表 - 只包含源码内部自己定义的,不包含继承来的
# 返回形式如下:
# [[导出变量数组],[onready变量数组],[普通全局变量数组]]
static func get_script_property_list(script:Script) -> Array:
	var source_code = script.source_code  # 源代码
	var regex = RegEx.new()
	regex.compile("(export var .*)|(export[(].*[)] var .*)|(onready var .*)|(\\tvar .*)|(var .*)")
	var results = regex.search_all(source_code)
	var export_var_names:PoolStringArray = []
	var onready_var_names:PoolStringArray = []
	var global_var_names:PoolStringArray = []
	for result in results:
		# 导出变量
		if result.get_string(1) != "":
			export_var_names.append(result.get_string(1))
		if result.get_string(2) != "":
			export_var_names.append(result.get_string(2))
		# onready变量
		if result.get_string(3) != "":
			onready_var_names.append(result.get_string(3))
		# 普通全局变量
		if result.get_string(5) != "":
			global_var_names.append(result.get_string(5))
	return [export_var_names,onready_var_names,global_var_names]
		
# 返回脚本的常量列表 - 只包含源码内部自己定义的,不包含继承来的
static func get_script_const_list(script:Script) -> PoolStringArray:
	var source_code = script.source_code  # 源代码
	var regex = RegEx.new()
	regex.compile("const (.*)")
	var results = regex.search_all(source_code)
	var const_names:PoolStringArray = []
	for result in results:
		const_names.append(result.get_string(1))
	return const_names

# 返回脚本的信号列表 - 只包含源码内部自己定义的,不包含继承来的
static func get_script_signal_list(script:Script) -> PoolStringArray:
	var source_code = script.source_code  # 源代码
	var regex = RegEx.new()
	regex.compile("\"signal (.*[(].*[)])\"|signal (.*[(].*[)])")
	var results = regex.search_all(source_code)
	var signal_names:PoolStringArray = []
	for result in results:
		if result.get_string(2) != "":
			signal_names.append(result.get_string(2))
	return signal_names

# =================== 额外需要的函数 ====================

# 保存字符串到指定路径的文件
static func saveString(path:String,content:String) -> void:
	var file = File.new()
	file.open(path,File.WRITE)
	file.store_string(content) # 整体存储
	file.close()
	
# 保存字符串到指定路径的文件
static func get_date_time() -> String:
	return Time.get_datetime_string_from_system().replace("T"," ")
	
	
	
	

猜你喜欢

转载自blog.csdn.net/graypigen1990/article/details/127033188