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:增加公式并运行代码,再鼠标单击全部公式后的界面
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于