Skip to content

Commit

Permalink
Merge pull request #736 from obgnail/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
obgnail authored Sep 5, 2024
2 parents 6a9e872 + 9422dbc commit a5a856b
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 79 deletions.
28 changes: 18 additions & 10 deletions plugin/custom/plugins/markdownLint/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class markdownLintPlugin extends BaseCustomPlugin {
<div class="plugin-markdownlint-icon ion-refresh" action="refresh" ty-hint="强制刷新"></div>
<div class="plugin-markdownlint-icon ion-code" action="toggleSourceMode" ty-hint="切换源码模式(也可以在表格中右键)"></div>
<div class="plugin-markdownlint-icon ion-wrench" action="fixAll" ty-hint="尽力修复规范错误"></div>
<div class="plugin-markdownlint-icon ion-information-circled" action="detailAll" ty-hint="详细信息"></div>
<div class="plugin-markdownlint-icon ion-earth" action="translate" ty-hint="翻译"></div>
<div class="plugin-markdownlint-icon ion-information-circled" action="detailAll" ty-hint="详细信息"></div>
<div class="plugin-markdownlint-icon ion-gear-b" action="settings" ty-hint="当前配置"></div>
<div class="plugin-markdownlint-icon ion-document-text" action="doc" ty-hint="规则文档"></div>
</div>
Expand Down Expand Up @@ -47,30 +47,38 @@ class markdownLintPlugin extends BaseCustomPlugin {
const _getDetail = (infos = this.errors) => {
const obj = infos.map(i => this.utils.fromObject(i, ["lineNumber", "ruleNames", "errorDetail", "errorContext", "errorRange", "fixInfo"]));
const content = JSON.stringify(obj.length === 1 ? obj[0] : obj, null, "\t");
const components = [{ label: "详细信息", type: "textarea", rows: 15, readonly: "readonly", content }];
this.utils.modal({ title: "格式规范检测", width: "550px", components });
const components = [{ label: "", type: "textarea", rows: 15, readonly: "readonly", content }];
this.utils.modal({ title: "详细信息", width: "550px", components });
}
const _showDoc = () => {
const url = "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md";
const onclick = ev => ev.target.closest("a") && this.utils.openUrl(url);
const content = JSON.stringify(this.l10n, null, "\t");
const components = [
{ label: "以下为简单说明,如需查看完整文档请 <a>前往网站</a>", type: "p", onclick },
{ label: "", type: "textarea", rows: 15, readonly: "readonly", content },
];
this.utils.dialog.modal({ title: "格式规范", width: "600px", components });
}

const _funcMap = {
close: () => this.callback(),
refresh: () => this.checkLintError(),
doc: () => this.utils.openUrl("https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md"),
doc: () => _showDoc(),
toggleSourceMode: () => File.toggleSourceMode(),
translate: () => {
this.config.translate = !this.config.translate;
this.checkLintError();
},
settings: () => {
const content = JSON.stringify(this.config.rule_config, null, "\t");
const components = [{ label: "当前配置", type: "textarea", rows: 15, readonly: "readonly", content }];
this.utils.modal({ title: "格式规范检测", width: "550px", components });
const components = [{ label: "", type: "textarea", rows: 15, readonly: "readonly", content }];
this.utils.modal({ title: "当前配置", width: "550px", components });
},
detailAll: () => _getDetail(this.errors),
detailSingle: infoIdx => _getDetail([this.errors[infoIdx]]),
fixAll: () => this.fixLintError(),
fixSingle: infoIdx => {
const errors = [this.errors[infoIdx]];
this.fixLintError(errors);
},
fixSingle: infoIdx => this.fixLintError([this.errors[infoIdx]]),
jumpToLine: lineToGo => {
if (!lineToGo) return;
if (!File.editor.sourceView.inSourceMode) {
Expand Down
46 changes: 23 additions & 23 deletions plugin/custom/plugins/markdownLint/l10n.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
module.exports = {
MD001: "标题级别应该逐级递增,不允许跳级",
MD001: "标题级别应该逐级递增,不可跳级",
MD002: "第一个标题应该是顶级标题",
MD003: "在标题前加#号来表示标题级别",
MD004: "要求采用一致的无序列表的格式",
MD003: "在标题前加#号以表示标题级别",
MD004: "要求采用一致的无序列表格式",
MD005: "要求同级列表项的缩进是一致的",
MD006: "最高级标题不能缩进",
MD007: "无序列表嵌套时,使用两个空格缩进",
MD007: "嵌套的无序列表要使用两个空格缩进",
MD008: "MD008",
MD009: "行尾最多可以添加两个空格,用于表示换行",
MD009: "行尾最多空两格,以示换行",
MD010: "不能使用tab缩进,要使用空格",
MD011: "内联形式的链接的中括号和圆括号使用错误",
MD011: "内联链接的中括号和圆括号使用错误",
MD012: "不能有连续的空行",
MD013: "行的长度应该在一定范围内",
MD014: "代码块中,终端命令除非后接其输出,否则前面不能有$符号",
MD014: "代码块中的终端命令除非后接其输出,否则不能前接$号",
MD015: "MD015",
MD016: "MD016",
MD017: "MD017",
MD018: "atx标题格式下,#号和文字之间需要一个空格隔开",
MD019: "atx标题格式下,#号和文字之间的空格不能多于一个",
MD020: "closed_atx标题格式下,文字和前后#号之间需用一个空格隔开",
MD021: "closed_atx标题格式下,文字和前后#号之间的空格不能多于一个",
MD022: "标题行的上下行应该都是空行",
MD018: "atx标题格式下,#号和文字之间需空一格",
MD019: "atx标题格式下,#号和文字之间只能空一格",
MD020: "closed_atx标题格式下,文字和#号之间需空一格",
MD021: "closed_atx标题格式下,文字和#号之间只能空一格",
MD022: "标题行的前后需要用空行隔开",
MD023: "标题行不能缩进",
MD024: "不能连续出现内容重复的标题",
MD025: "只能有一个一级标题",
MD026: "标题不应以标点符号结尾",
MD027: "引用区块的引用符号和文字之间有且只有一个空格",
MD028: "两个引用区块间不能用空行隔开。引用区块中的空行要用>开头",
MD029: "要求有序列表的序号从1开始,按顺序递增",
MD030: "列表的每一列表项的标识符后只能空一格,后接列表内容",
MD031: "单独的代码块前后需要用空行隔开",
MD032: "列表前后需要用空行隔开,列表的缩进必须一致",
MD027: "引用区块的引用符号和文字之间需空一格",
MD028: "引用区块之间的空行要以>开头",
MD029: "要求有序列表的序号从1开始,按序递增",
MD030: "列表项标识符后只能空一格,后接列表内容",
MD031: "单独的代码块前后需用空行隔开",
MD032: "列表前后需用空行隔开,列表的缩进必须一致",
MD033: "不建议使用HTML语句",
MD034: "单纯的链接地址需要用尖括号包裹",
MD035: "要求采用一致的水平线格式",
Expand All @@ -39,22 +39,22 @@ module.exports = {
MD038: "反引号的内侧不应紧邻空格",
MD039: "链接中,中括号的内侧不应紧邻空格",
MD040: "代码块应该指定编程语言",
MD041: "文档正文一开始必须是一级标题",
MD041: "文档正文必须以一级标题开始",
MD042: "链接的地址不能为空",
MD043: "要求标题遵循一定的结构",
MD043: "要求标题遵循约定的结构",
MD044: "大小写错误",
MD045: "图片链接必须包含描述文本",
MD046: "代码块要用三个反引号包裹",
MD047: "文档末尾需要一个空行结尾",
MD048: "要求采用一致的代码块分隔符",
MD049: "要求采用一致的斜体格式",
MD050: "要求采用一致的加粗格式",
MD051: "文内链接必须有效,不能指向一个不存在的标题",
MD052: "引用链接和图片应该使用已经定义的标签",
MD051: "文内链接必须有效",
MD052: "引用链接和图片应使用已经定义的标签",
MD053: "链接和图片引用定义不可省略",
MD054: "要求采用一致的链接和图片格式",
MD055: "要求采用一致的表格分隔符格式",
MD056: "表格列数要求是一致的,不能省略或多余",
MD056: "表格列数必须一致的",
MD057: "MD057",
MD058: "表格前后需要用空行隔开",
};
72 changes: 37 additions & 35 deletions plugin/custom/plugins/resourceOperation.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ class resourceOperationPlugin extends BaseCustomPlugin {
this.regexp = ignore_img_html_element
? new RegExp("!\\[.*?\\]\\((?<src1>.*)\\)", "g")
: new RegExp("!\\[.*?\\]\\((?<src1>.*)\\)|<img.*?src=\"(?<src2>.*?)\"", "g")
this.resourceSuffix = new Set(resource_suffix);
this.fileSuffix = new Set(markdown_suffix);
this.resourceSuffixs = new Set(resource_suffix);
this.fileSuffixs = new Set(markdown_suffix);
this.resources = new Set();
this.resourcesInFile = new Set();
if (collect_file_without_suffix) {
this.resourceSuffix.add("");
this.resourceSuffixs.add("");
}
this.nonExistInFile = null;
this.nonExistInFolder = null;
Expand Down Expand Up @@ -77,10 +77,10 @@ class resourceOperationPlugin extends BaseCustomPlugin {
if (!target) return;
const tr = target.closest("tr");
if (!tr) return;
const p = tr.querySelector(".plugin-resource-operation-src");
if (!p) return;
const img = tr.querySelector("img");
if (!img) return;

const src = p.dataset.path;
const src = img.getAttribute("src");
const action = target.getAttribute("action");
if (action === "delete") {
if (this.showWarnDialog) {
Expand Down Expand Up @@ -126,21 +126,22 @@ class resourceOperationPlugin extends BaseCustomPlugin {
delete output.resource_non_exist_in_file;
delete output.resource_non_exist_in_folder;
const replacer = (key, value) => Array.isArray(value) ? value.join("|") : value

const btnGroup = `<td><div class="btn-group"><button type="button" class="btn btn-default" action="locate">打开</button><button type="button" class="btn btn-default" action="delete">删除</button></div></td>`
const rows = Array.from(this.nonExistInFile, (row, idx) => `<tr><td>${idx + 1}</td><td class="plugin-resource-operation-src" data-path="${row}">${row}</td>${btnGroup}</tr>`)
const nonExistInFile = Array.from(this.nonExistInFile, (row, idx) => `<tr><td>${idx + 1}</td><td>${row}</td><td class="plugin-common-hidden"><img src="${row}"/></td>${btnGroup}</tr>`)
const nonExistInFolder = Array.from(this.nonExistInFolder, (row, idx) => `<tr><td>${idx + 1}</td><td>${row}</td></tr>`)

this.entities.wrap.innerHTML = `
<table class="table">
<table class="table non-exist-in-file-table">
<caption>存在于文件夹但不存在于md文件的资源(共${this.nonExistInFile.size}项)</caption>
<thead><tr><th>#</th><th>resource</th><th style="min-width: 130px">operation</th></tr></thead>
<tbody>${rows.join("")}</tbody>
<thead><tr><th>#</th><th>resource</th><th class="plugin-common-hidden">preview</th><th>operation</th></tr></thead>
<tbody>${nonExistInFile.join("")}</tbody>
</table>
<table class="table">
<caption>存在于md文件但不存在于文件夹的资源(共${this.nonExistInFolder.size}项)</caption>
<thead><tr><th>#</th><th>resource</th></tr></thead>
<tbody>${Array.from(this.nonExistInFolder, (row, idx) => `<tr><td>${idx + 1}</td><td>${row}</td></tr>`).join("")}</tbody>
<tbody>${nonExistInFolder.join("")}</tbody>
</table>
<div class="plugin-resource-operation-message">配置</div>
<textarea rows="10" readonly>${JSON.stringify(output, replacer, "\t")}</textarea>
`
Expand All @@ -157,8 +158,10 @@ class resourceOperationPlugin extends BaseCustomPlugin {
togglePreview = force => {
const icon = this.entities.iconGroup.querySelector('[action="togglePreview"]');
const wantClose = force === false || icon.classList.contains("ion-eye");
this.entities.wrap.querySelectorAll(".non-exist-in-file-table td:nth-of-type(3), .non-exist-in-file-table th:nth-of-type(3)")
.forEach(e => e.classList.toggle("plugin-common-hidden", wantClose));
const func = wantClose ? "off" : "on";
const className = ".plugin-resource-operation-src";
const className = "img";
this.entities.$wrap
[func]("mouseover", className, this._showPopup)
[func]("mouseout", className, this._hidePopup)
Expand All @@ -171,7 +174,7 @@ class resourceOperationPlugin extends BaseCustomPlugin {
const popup = this.entities.popup;
if (!popup) return;

popup.src = ev.target.dataset.path;
popup.src = ev.target.getAttribute("src");
const left = Math.min(window.innerWidth - 10 - popup.offsetWidth, ev.clientX + 10);
const top = Math.min(window.innerHeight - 50 - popup.offsetHeight, ev.clientY + 20);
popup.style.left = `${left}px`;
Expand All @@ -182,8 +185,8 @@ class resourceOperationPlugin extends BaseCustomPlugin {

getOutput = () => ({
search_folder: this.utils.getMountFolder(),
resource_suffix: Array.from(this.resourceSuffix),
markdown_suffix: Array.from(this.fileSuffix),
resource_suffix: Array.from(this.resourceSuffixs),
markdown_suffix: Array.from(this.fileSuffixs),
ignore_img_html_element: this.config.ignore_img_html_element,
collect_file_without_suffix: this.config.collect_file_without_suffix,
ignore_folders: this.config.ignore_folders,
Expand Down Expand Up @@ -265,40 +268,39 @@ Designed with ♥ by [obgnail](https://github.com/obgnail/typora_plugin)
return imagePath;
}

const collectMatch = async content => {
for (const match of content.matchAll(this.regexp)) {
const collectMatch = content => {
return Promise.all(content.matchAll(this.regexp).map(async match => {
let src = match.groups.src1 || match.groups.src2;
if (!src || isNetworkImage(src) || isSpecialImage(src)) continue;
if (!src || isNetworkImage(src) || isSpecialImage(src)) return;

try {
src = decodeURI(src).split("?")[0];
src = decodeURIComponent(src).split("?")[0];
} catch (e) {
console.warn("error path:", src);
continue
return;
}

src = resolve(dir, src);
if (this.resourcesInFile.has(src)) continue;
if (this.resourcesInFile.has(src)) return;

const resourcePath = await getRealPath(src);
this.resourcesInFile.add(resourcePath);

if (this.resourceSuffixs.has(extname(resourcePath).toLowerCase())) {
this.resourcesInFile.add(resourcePath);
}
const remain = src.slice(resourcePath.length);
if (remain) {
await collectMatch(remain + ")");
}
}
}))
}

const ext = extname(filePath).toLowerCase();
if (this.resourceSuffix.has(ext)) {
if (this.resourceSuffixs.has(ext)) {
this.resources.add(filePath);
return
} else if (this.fileSuffixs.has(ext)) {
const buffer = await readFile(filePath);
await collectMatch(buffer.toString());
}
if (!this.fileSuffix.has(ext)) return;

const buffer = await readFile(filePath);
await collectMatch(buffer.toString());
}

traverseDir = async (dir, callback) => {
Expand All @@ -307,15 +309,15 @@ Designed with ♥ by [obgnail](https://github.com/obgnail/typora_plugin)

async function traverse(dir) {
const files = await readdir(dir);
for (const file of files) {
await Promise.all(files.map(async file => {
const filePath = join(dir, file);
const stats = await stat(filePath);
if (stats.isFile()) {
await callback(filePath, dir)
await callback(filePath, dir);
} else if (stats.isDirectory() && !ignore_folders.includes(file)) {
await traverse(filePath);
}
}
}))
}

await traverse(dir);
Expand Down
9 changes: 4 additions & 5 deletions plugin/file_counter.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ class fileCounterPlugin extends BasePlugin {

async function traverse(dir) {
const stats = await promises.stat(dir);
if (!stats.isDirectory()) {
return;
}
if (!stats.isDirectory()) return;

const files = await promises.readdir(dir);
for (const file of files) {
await Promise.all(files.map(async file => {
const filePath = Path.join(dir, file);
const fileStats = await promises.stat(filePath);
if (fileStats.isFile() && fileFilter(filePath, fileStats)) {
Expand All @@ -78,7 +77,7 @@ class fileCounterPlugin extends BasePlugin {
if (fileStats.isDirectory() && dirFilter(file)) {
await traverse(filePath);
}
}
}))
}

traverse(dir).then(() => then(fileCount)).catch(err => console.error(err));
Expand Down
25 changes: 22 additions & 3 deletions plugin/global/styles/resourceOperation.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,35 @@
}

#plugin-resource-operation .plugin-resource-operation-popup {
max-width: 400px;
max-height: 400px;
max-width: 500px;
max-height: 500px;
position: fixed;
box-shadow: 0 0 0.125em 0 rgba(0, 0, 0, .5);
border-radius: 0.5em;
background-color: var(--side-bar-bg-color);
z-index: 9999;
}

#plugin-resource-operation td {
.non-exist-in-file-table th:first-child {
width: 10px;
}
.non-exist-in-file-table th:last-child {
width: 150px;
}
.non-exist-in-file-table td:nth-of-type(2) {
max-width: 200px;
white-space: break-spaces;
word-break: break-word;
}
.non-exist-in-file-table td:nth-of-type(3) {
max-width: 100px;
max-height: 100px;
}
.non-exist-in-file-table td:last-of-type {
text-align: center;
}

#plugin-resource-operation tbody {
font-size: 0.7em;
}

Expand Down
7 changes: 4 additions & 3 deletions plugin/search_multi.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,16 @@ class searchMultiKeywordPlugin extends BasePlugin {

async function traverse(dir) {
const files = await readdir(dir);
for (const file of files) {
await Promise.all(files.map(async file => {
const filePath = Path.join(dir, file);
const stats = await stat(filePath);
if (stats.isFile() && (!fileFilter || fileFilter(filePath, stats))) {
readFile(filePath).then(buffer => callback(filePath, stats, buffer)).catch(console.error);
const buffer = await readFile(filePath);
callback(filePath, stats, buffer);
} else if (stats.isDirectory() && (!dirFilter || dirFilter(file))) {
await traverse(filePath);
}
}
}))
}

traverse(dir).then(then).catch(console.error);
Expand Down

0 comments on commit a5a856b

Please sign in to comment.