对图、表和公式的自动编号和交叉引用是科研笔记最基本的功能,但当前各种笔记系统均未实现该功能。因此,抽出一天时间,利用 Quicker 并结合 C#代码,针对 Siyuan 做了一下尝试。虽然还有待完善,但也基本实现了该功能,见图 11。
交叉引用 - 动作信息 - Quicker (getquicker.net)
主要功能:
-
实现对图进行自动编号,同时增减图刷新后,编号将进行全自动更新;
-
实现对表进行自动编号,同时增减表刷新后,编号将进行全自动更新;
-
实现对公式进行自动编号,同时增减公式刷新后,编号将进行全自动更新;
-
实现了对图表和公式的交叉引用,同时增删图表和公式后将自动更新交叉引用
图 1 界面
主要代码如下:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; public static string Exec(string paramValue) { JObject Jobj=JObject.Parse(paramValue); string block_id = (string)Jobj["block_id"]; string API_token= (string)Jobj["API_token"]; string cmd = (string)Jobj["cmd"]; string data = (string)Jobj["data"]; if (cmd.ToLower()=="setcaption"){ SetCaption(data, block_id,API_token); } else if (cmd.ToLower()=="clear"){ ClearCaptionInfo(block_id,API_token); } else if (cmd.ToLower()=="update") { UpdateCaptions(block_id,API_token); } return ""; } private static Dictionary<string, string> ial2JSON(string ial, string mk) { Dictionary<string, string> mydict = new Dictionary<string, string>(); foreach (Match m in Regex.Matches(ial, "([\\w-]+)=\"([^\"]*)\"")) { mydict.Add(m.Groups[1].Value, m.Groups[2].Value); } mydict.Add("mk", mk); return mydict; } public static string ClearCaptionInfo(string block_id, string Token) { SYAPI siyuanAPI = new SYAPI(Token); JObject myJobj = new JObject(); myJobj["custom-type"] = ""; myJobj["custom-id"] = ""; myJobj["name"] = ""; siyuanAPI.SetBlockAttrs(block_id, myJobj); siyuanAPI.PushMsg("已完成更新!"); return ""; } public static string SetCaption(string CaptionLabel, string block_id, string Token) { SYAPI siyuanAPI = new SYAPI(Token); JObject result=siyuanAPI.SQL_query(string.Format("Select markdown from blocks where id='{0}'", block_id)); string cmk = (string)result["data"][0]["markdown"]; Dictionary<string, string> cdict = new Dictionary<string, string>() { { "custom-type",CaptionLabel}, { "custom-id","1"}, { "name",CaptionLabel+" 1"}, { "id",block_id}, { "mk",cmk} }; string doc_id = siyuanAPI.GetDocumentIDbyBlockID(block_id); result = siyuanAPI.SQL_query(string.Format("select markdown,ial from blocks where id in (SELECT block_id FROM attributes where name='custom-type' and root_id='{0}') ", doc_id)); List<Dictionary<string, string>> data = result["data"].Select(x => ial2JSON((string)x["ial"], (string)x["markdown"])).ToList<Dictionary<string, string>>(); data.Add(cdict); result = siyuanAPI.GetChildBlocks(doc_id); List<string> idx = result["data"].Select(x => (string)x["id"]).ToList<string>(); data = data.OrderBy(mdict => idx.IndexOf(mdict["id"])).ToList(); Dictionary<string, int> CaptionDictID = new Dictionary<string, int>(); foreach (Dictionary<string, string> item in data) { string captionLabel = item["custom-type"]; int seqID = int.Parse(item["custom-id"]); string id = item["id"]; string name = item["name"]; string mk = item["mk"]; if (CaptionDictID.Keys.Contains(captionLabel)) { CaptionDictID[captionLabel] += 1; } else { CaptionDictID[captionLabel] = 1; } if ((new string[] { "式", "equation", "eq", "eq.", "公式" }).Contains(captionLabel.ToLower())) { mk = Regex.Replace(mk, "^\\$\\$", ""); mk = Regex.Replace(mk, "\\$\\$$", ""); mk = Regex.Replace(mk.Trim(), @"\\tag ?\{ ?(\d+-)?\d+ ?\}", ""); name = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.UpdateBlock(id, string.Format("$${0}\\tag{{{1}{2}}}$$", mk.Trim(), "", CaptionDictID[captionLabel])); } else { string pattern = string.Format("^(?<header>[#\\* ]*)(?<CaptionLabel>{0} \\d{{1,3}})?(?<last>.*)$", captionLabel); GroupCollection groups = Regex.Match(mk, pattern).Groups; mk = groups["header"].ToString().Trim() + captionLabel + " " + CaptionDictID[captionLabel].ToString() + " " + groups["last"].ToString().Trim(); siyuanAPI.UpdateBlock(id, mk); } JObject myJobj = new JObject(); myJobj["custom-type"] = captionLabel; myJobj["custom-id"] = CaptionDictID[captionLabel].ToString(); myJobj["name"] = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.SetBlockAttrs(id, myJobj); } return ""; } public static void UpdateCaptions(string block_id, string Token) { SYAPI siyuanAPI = new SYAPI(Token); string doc_id = siyuanAPI.GetDocumentIDbyBlockID(block_id); JObject result = siyuanAPI.SQL_query(string.Format("select markdown,ial from blocks where id in (SELECT block_id FROM attributes where name='custom-type' and root_id='{0}') ", doc_id)); List<Dictionary<string, string>> data = result["data"].Select(x => ial2JSON((string)x["ial"], (string)x["markdown"])).ToList<Dictionary<string, string>>(); result = siyuanAPI.GetChildBlocks(doc_id); List<string> idx = result["data"].Select(x => (string)x["id"]).ToList<string>(); data = data.OrderBy(mdict => idx.IndexOf(mdict["id"])).ToList(); Dictionary<string, int> CaptionDictID = new Dictionary<string, int>(); foreach (Dictionary<string, string> item in data) { string captionLabel = item["custom-type"]; int seqID = int.Parse(item["custom-id"]); string id = item["id"]; string name = item["name"]; string mk = item["mk"]; if (CaptionDictID.Keys.Contains(captionLabel)) { CaptionDictID[captionLabel] += 1; } else { CaptionDictID[captionLabel] = 1; } if ((new string[] { "式", "equation", "eq", "eq.", "公式" }).Contains(captionLabel.ToLower())) { mk = Regex.Replace(mk, "^\\$\\$", ""); mk = Regex.Replace(mk, "\\$\\$$", ""); mk = Regex.Replace(mk.Trim(), @"\\tag ?\{ ?(\d+-)?\d+ ?\}", ""); name = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.UpdateBlock(id, string.Format("$${0}\\tag{{{1}{2}}}$$", mk.Trim(), "", CaptionDictID[captionLabel])); } else { string pattern = string.Format("^(?<header>[#\\* ]*)(?<CaptionLabel>{0} \\d{{1,3}})?(?<last>.*)$", captionLabel); GroupCollection groups = Regex.Match(mk, pattern).Groups; mk = groups["header"].ToString().Trim() + captionLabel + " " + CaptionDictID[captionLabel].ToString() + " " + groups["last"].ToString().Trim(); siyuanAPI.UpdateBlock(id, mk); } JObject myJobj = new JObject(); myJobj["custom-type"] = captionLabel; myJobj["custom-id"] = CaptionDictID[captionLabel].ToString(); myJobj["name"] = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.SetBlockAttrs(id, myJobj); } siyuanAPI.PushMsg("已完成更新!"); } public class SYAPI { private string _TokenID; public SYAPI(string TokenID) { _TokenID = TokenID; } private async Task<JObject> CommandAsync(string path, JObject data) { string url = "http://127.0.0.1:6806"; url = url + path; var body = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json"); using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Add("Authorization", "Token " + _TokenID); HttpResponseMessage response = await client.PostAsync(url, body); response.EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); return (JObject.Parse(responseBody)); } } public JObject lsNotebooksAsync() { return (CommandAsync("/api/notebook/lsNotebooks", new JObject()).Result); } public JObject PushMsg(string msg) { return CommandAsync("/api/notification/pushMsg", JObject.FromObject(new { msg = msg, timeout = 7000 })).Result; } public JObject PushErrMsg(string msg) { return CommandAsync("/api/notification/pushMsg", JObject.FromObject(new { msg = msg, timeout = 7000 })).Result; } public JObject SQL_query(string SQL) { return CommandAsync("/api/query/sql", JObject.FromObject(new { stmt = SQL, })).Result; } #region Block块 public JObject UpdateBlock(string block_id, string markdown, string dataType = "markdown") { return CommandAsync("/api/block/updateBlock", JObject.FromObject(new { id = block_id, dataType = dataType, data = markdown })).Result; } public JObject GetBlockInfo(string block_id) { return CommandAsync("/api/block/getBlockInfo", JObject.FromObject(new { id = block_id, })).Result; } public JObject GetBlockKramdown(string block_id) { return CommandAsync("/api/block/getBlockKramdown", JObject.FromObject(new { id = block_id, })).Result; } public JObject GetChildBlocks(string block_id) { return CommandAsync("/api/block/getChildBlocks", JObject.FromObject(new { id = block_id })).Result; } public JObject SetBlockAttrs(string block_id, object dict) { return CommandAsync("/api/attr/setBlockAttrs", JObject.FromObject(new { id = block_id, attrs = JObject.FromObject(dict), })).Result; } public JObject ResetBlockAttrs(string block_id, object dict) { return CommandAsync("/api/attr/resetBlockAttrs", JObject.FromObject(new { id = block_id, attrs = JObject.FromObject(dict), })).Result; } #endregion #region Document public string GetDocumentIDbyBlockID(string block_id) { JObject result = SQL_query(string.Format(" select root_id from blocks where id='{0}'", block_id)); return (string)result["data"][0]["root_id"]; } #endregion }
图 1 界面 ↩
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于