1. 公式编号
首先感谢思源笔记对公式编号的支持,通过 y=x^2\tag{1-1}
、z=i+A\cdot x\tag{1-2}
、E=m\cdot C^2\tag{1-3}
、y=A \cdot sin(x)\tag{1-4}
,可以很轻松实现公式 1-1 至 1-4,并进行编号。
图 1:公式编号
2. 公式交叉引用
如果对每个公式属性进行了赋值(图 3),那么后续在任意地方使用 (( eq: 1-1
或者 [[eq:1-1
可按照图 2 格式引用公式 1-1,实现对公式的交叉引用。后续因其他需要对属性进行修改,引用文本也会自动更新。通过这种思路,实际上就可以实现所有图、表、公式的交叉引用了。如果通过编写插件,实现整个过程的全自动,思源笔记就可真正意义上用于科研笔记,或者进行正规教材/学术论文的编写了。
图 2:公式交叉引用
图 3:对每个公式属性进行定义
3. 问题
现在遇到的问题是:通过鼠标手动更改属性,所有公式引用编号会自动更新,但通过 Siyuan API 函数 setBlockAttrs
修改属性,引用文本并不更新(尽管属性已经更新了)。重启或者按 F5 刷新都不好使。目前只有通过鼠标挨个点击一遍公式才能实现更新,但这样徒增太多不必要的操作了。
@88250 请问这是不是 Siyuan 的一个 bug,还是在调用 setBlockAttrs 修改属性后,还需要调用什么函数,激活所有引用文本的更新?
4 问题重现
下面是拟实现 Siyuan 公式交叉引用的 python 代码。该代码实现了增减公式时公式编号自动变更问题,实现了公式属性更新和交叉引用。现在唯一的问题是,增减公式时,需要通过鼠标挨个点击一遍公式,才能实现所有公式引用文本的更新。
如果公式交叉引用问题解决了,图表的交叉引用也就一并解决了。
import json
import requests
import win32con
import win32gui
import win32api
import win32process
import win32com
import win32com.client
import time
import pyperclip
import os
import sys
import re
# 要求当前文档中含有公式,否则会出错。
TokenID: str = "" # 自己的TokenID
class SiYunNoteBook:
def __init__(self, TokenID) -> None:
self.TokenID = TokenID
def Command(self, url: str, data=None, indent=False):
headers = {
"Content-Type": "application/javascript",
"Authorization": f"Token { self.TokenID }"
}
Result = requests.post(f"http://localhost:6806{ url }",
headers=headers, data=json.dumps(data))
if indent:
return (json.dumps(json.loads(Result.text), indent=True, ensure_ascii=False))
else:
return json.loads(Result.text)
def pushMsg(self, Msg: str):
return self.Command("/api/notification/pushMsg",
data={"msg": Msg, "timeout": 7000}
)
def pushErrMsg(self, Msg: str):
return self.Command("/api/notification/pushErrMsg",
data={"msg": Msg, "timeout": 7000}
)
return self.Command("/api/file/getFile",
data={"path": file}
)
def SQL_query(self, SQL: str):
return self.Command("/api/query/sql",
data={"stmt": SQL})
def setBlockAttrs(self, block_id: str, dict: dict):
return self.Command("/api/attr/setBlockAttrs",
data={"id": block_id,
"attrs": dict
})
def updateBlock(self, doc_id: str, data, dataType: str = "markdown"):
return self.Command("/api/block/updateBlock",
data={"id": doc_id,
"dataType": dataType,
"data": data
}
)
def getDocumentIDbyBlock(self, block_id):
result = self.SQL_query(
f"SELECT root_id FROM blocks where id= '{ block_id }'")
return (result["data"][0]["root_id"])
def getCurrentBlockID(self) -> str:
def StopAndShowQuickerMessage(message: str):
os.system(f'start quicker:showmessage:error:"{message}"')
sys.exit()
def find_process(exe_name):
hwnd_list = []
win32gui.EnumWindows(
lambda _hwnd, _hwnd_list: _hwnd_list.append(_hwnd), hwnd_list)
app_hwnd = None
app_pid = None
for hwnd in hwnd_list:
app_pid, procname = get_process_name(hwnd)
if procname.find(exe_name) > 0:
app_hwnd = hwnd
# print(procname)
break
if not app_hwnd:
print("没打开Siyuan笔记!")
return app_pid, app_hwnd
def get_process_name(hwnd):
try:
threadpid, procpid = win32process.GetWindowThreadProcessId(
hwnd)
mypyproc = win32api.OpenProcess(
win32con.PROCESS_ALL_ACCESS, False, procpid)
procname = win32process.GetModuleFileNameEx(mypyproc, 0)
return procpid, procname
except:
return {0, "noprocname"}
app_pid, app_hwnd = find_process("SiYuan.exe")
if not app_hwnd:
StopAndShowQuickerMessage("请确认Siyuan应用程序已打开! ")
block_id: str = ""
win32gui.SetForegroundWindow(app_hwnd)
shell = win32com.client.Dispatch('WScript.Shell')
shell.SendKeys("^+h", 0)
time.sleep(0.3)
siyuanLink: str = pyperclip.paste()
if not siyuanLink.startswith("siyuan://blocks/"):
StopAndShowQuickerMessage("没找到Block_ID")
return (os.path.basename(siyuanLink))
def getChildBlocks(self, block_id: str):
return self.Command("/api/block/getChildBlocks", data={"id": block_id})
def refreshBacklink(self, block_id: str):
return self.Command("/api/ref/refreshBacklink", data={"id": block_id})
SY = SiYunNoteBook(TokenID)
block_id: str = SY.getCurrentBlockID()
doc_id: str = SY.getDocumentIDbyBlock(block_id)
result = SY.SQL_query(
f"""
Select id, markdown, name from blocks
where root_id == '{doc_id}'
and type=='m'
"""
)
blocklist = {item["id"]: item for item in result["data"]}
# 按照文档调整顺序
idx = [item["id"] for item in SY.getChildBlocks(
doc_id)["data"] if item["id"] in blocklist]
result = [blocklist[i] for i in idx]
label: str = "1-"
seqID: int = 1
for item in result:
id, mk, name = item.values()
mk = mk.strip("$$").strip("\n").strip(" ")
mk = re.sub(r'\\tag\{ ?(\d+-)\d+ ?\}', "", mk)
NameLabel: str = f"{label}{seqID}"
SY.updateBlock(id, rf"$${mk}\tag{{{label}{seqID}}}$$")
SY.setBlockAttrs(id, {"name": NameLabel, "alias": f"eq:{NameLabel}"})
seqID += 1
增减公式并运行代码后,引用文本直接变成图 4 所示了。鼠标挨个点击公式后,才会变成图 5。
图 4:增减公式并运行代码后的界面
图 5:增加公式并运行代码,再鼠标单击全部公式后的界面
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于