对图、表和公式的自动编号和交叉引用是科研笔记最基本的功能,但当前各种笔记系统均未实现该功能。因此,抽出一天时间,利用 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 界面 ↩
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于