修复问题
- 修复了 rofi 前端编辑文件时的填充、提取json信息的问题 - 修复了后端在处理编辑文件请求时,会清空Language信息的问题
This commit is contained in:
@@ -32,8 +32,8 @@ public class SnippetManager {
|
|||||||
File file = new File(System.getenv(Constant.Property.DIR));
|
File file = new File(System.getenv(Constant.Property.DIR));
|
||||||
HashMap<String, String> map = new HashMap<>();
|
HashMap<String, String> map = new HashMap<>();
|
||||||
for (File f : Objects.requireNonNull(file.listFiles())) {
|
for (File f : Objects.requireNonNull(file.listFiles())) {
|
||||||
if (f.isDirectory()){
|
if (f.isDirectory()) {
|
||||||
listFileStatus(f,map);
|
listFileStatus(f, map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
@@ -92,6 +92,11 @@ public class SnippetManager {
|
|||||||
|
|
||||||
Snippet snippet = new Snippet();
|
Snippet snippet = new Snippet();
|
||||||
BeanUtil.copyProperties(entity, snippet);
|
BeanUtil.copyProperties(entity, snippet);
|
||||||
|
FileReader reader = new FileReader(entity.getPath(), StandardCharsets.UTF_8);
|
||||||
|
String s = reader.readAllAsString();
|
||||||
|
Snippet primarySnippet = snippetReader.visit(s);
|
||||||
|
snippet.setLanguage(primarySnippet.getLanguage());
|
||||||
|
reader.close();
|
||||||
|
|
||||||
Files.move(p, Paths.get(tempPath), StandardCopyOption.REPLACE_EXISTING);
|
Files.move(p, Paths.get(tempPath), StandardCopyOption.REPLACE_EXISTING);
|
||||||
Files.writeString(p, snippet.toMarkdown(), StandardCharsets.UTF_8);
|
Files.writeString(p, snippet.toMarkdown(), StandardCharsets.UTF_8);
|
||||||
@@ -118,7 +123,7 @@ public class SnippetManager {
|
|||||||
List<RebuildEntity> list = new ArrayList<>();
|
List<RebuildEntity> list = new ArrayList<>();
|
||||||
File file = new File(System.getenv(Constant.Property.DIR));
|
File file = new File(System.getenv(Constant.Property.DIR));
|
||||||
for (File f : Objects.requireNonNull(file.listFiles())) {
|
for (File f : Objects.requireNonNull(file.listFiles())) {
|
||||||
listAll(f,list);
|
listAll(f, list);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,11 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from common.constant import editor_class, code_snippet_editor
|
from common.constant import editor_class, code_snippet_editor
|
||||||
|
|
||||||
from common.constant import template_add, template_edit
|
from common.constant import template_add, template_edit
|
||||||
from entity.result import ActionResult
|
from entity.result import ActionResult
|
||||||
from helper.api_helper import run_edit, run_add
|
from helper.api_helper import run_edit, run_add
|
||||||
@@ -73,13 +70,38 @@ def _parse_add(file_path: str) -> str:
|
|||||||
return _parse_add_text(text)
|
return _parse_add_text(text)
|
||||||
|
|
||||||
|
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
def _collect_indented_items(lines: List[str], start_idx: int) -> List[str]:
|
||||||
|
"""
|
||||||
|
从 lines[start_idx+1:] 开始收集“缩进的 - item”:
|
||||||
|
- 只有匹配 ^[ \t]+-\s*(.+) 的行才被收集
|
||||||
|
- 遇到下一个顶层的 '-'(未缩进)或标题行(如 ## ...)或空行则停止
|
||||||
|
"""
|
||||||
|
items = []
|
||||||
|
i = start_idx + 1
|
||||||
|
while i < len(lines):
|
||||||
|
line = lines[i]
|
||||||
|
m = re.match(r'^[ \t]+-\s*(.+?)\s*$', line)
|
||||||
|
if m:
|
||||||
|
val = m.group(1).strip()
|
||||||
|
if val:
|
||||||
|
items.append(val)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
# 遇到新的顶层 bullet 或标题或空行 => 离开段落
|
||||||
|
if re.match(r'^\s*-\s*\S', line) or re.match(r'^\s*##\s+', line) or line.strip() == '':
|
||||||
|
break
|
||||||
|
break
|
||||||
|
return items
|
||||||
|
|
||||||
def _prefill_edit(file_path: str, source_path: str, _id: str) -> None:
|
def _prefill_edit(file_path: str, source_path: str, _id: str) -> None:
|
||||||
# 将原始文件内容与元信息写入模板占位
|
|
||||||
# 读取原文件
|
|
||||||
src = Path(source_path).read_text(encoding='utf-8')
|
src = Path(source_path).read_text(encoding='utf-8')
|
||||||
|
|
||||||
# 提取代码块(仅代码,不带多余模板)与语言
|
# 提取代码块(兼容 ```[Lang] 或 ```lang 或 ```)
|
||||||
code_block = re.search(r"```(?:\[([^\]]*)\]|([A-Za-z0-9_+\-]+))?\s*\r?\n([\s\S]*?)```", src)
|
code_block = re.search(r"```(?:\[\s*([^\]]+?)\s*\]|([A-Za-z0-9_+\-]+))?\s*\r?\n([\s\S]*?)```", src)
|
||||||
language = ''
|
language = ''
|
||||||
code_only = ''
|
code_only = ''
|
||||||
if code_block:
|
if code_block:
|
||||||
@@ -89,26 +111,19 @@ def _prefill_edit(file_path: str, source_path: str, _id: str) -> None:
|
|||||||
if not code_only:
|
if not code_only:
|
||||||
code_only = src.strip()
|
code_only = src.strip()
|
||||||
|
|
||||||
# 从源文档的 MetaData 段提取 tags 与 description
|
# 从源文档的 MetaData 段提取 tags 与 description(**不再读取 Language**)
|
||||||
tags: list[str] = []
|
tags: List[str] = []
|
||||||
desc = ''
|
desc = ''
|
||||||
# 定位 MetaData 段
|
|
||||||
meta_match = re.search(r"##\s*MetaData([\s\S]*)", src)
|
meta_match = re.search(r"##\s*MetaData([\s\S]*)", src)
|
||||||
meta = meta_match.group(1) if meta_match else ''
|
meta = meta_match.group(1) if meta_match else ''
|
||||||
if meta:
|
if meta:
|
||||||
# Tags 段
|
lines = meta.splitlines()
|
||||||
tags_section = re.search(r"-\s*Tags\s*([\s\S]*?)(?:\n-\s*Description|\Z)", meta)
|
for idx, line in enumerate(lines):
|
||||||
if tags_section:
|
if re.match(r'^\s*-\s*Tags\s*$', line):
|
||||||
for line in tags_section.group(1).splitlines():
|
tags = _collect_indented_items(lines, idx)
|
||||||
m = re.match(r"^\s*-\s*(.+)$", line)
|
elif re.match(r'^\s*-\s*Description\s*$', line):
|
||||||
if m:
|
desc_lines = _collect_indented_items(lines, idx)
|
||||||
val = m.group(1).strip()
|
desc = ' '.join(desc_lines).strip()
|
||||||
if val:
|
|
||||||
tags.append(val)
|
|
||||||
# Description 段
|
|
||||||
desc_section = re.search(r"-\s*Description\s*\n\s*-\s*(.+)", meta)
|
|
||||||
if desc_section:
|
|
||||||
desc = desc_section.group(1).strip()
|
|
||||||
|
|
||||||
# 若语言未能从代码块检测,则用路径上级名兜底
|
# 若语言未能从代码块检测,则用路径上级名兜底
|
||||||
if not language:
|
if not language:
|
||||||
@@ -131,41 +146,64 @@ def _prefill_edit(file_path: str, source_path: str, _id: str) -> None:
|
|||||||
else:
|
else:
|
||||||
rebuilt_lines.append(" - \n - \n")
|
rebuilt_lines.append(" - \n - \n")
|
||||||
rebuilt_lines.append("- Description\n")
|
rebuilt_lines.append("- Description\n")
|
||||||
rebuilt_lines.append(f" - {desc}\n")
|
if desc:
|
||||||
|
rebuilt_lines.append(f" - {desc}\n")
|
||||||
|
else:
|
||||||
|
rebuilt_lines.append(" - \n")
|
||||||
|
|
||||||
Path(file_path).write_text(''.join(rebuilt_lines), encoding='utf-8')
|
Path(file_path).write_text(''.join(rebuilt_lines), encoding='utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_indented_list(lines: List[str], start_idx: int) -> List[str]:
|
||||||
|
"""
|
||||||
|
从 start_idx+1 开始收集缩进的 '- item' 条目(例如两格或更多缩进),
|
||||||
|
遇到下一个顶层 '- Something'、'## ' 标题或空行则停止。
|
||||||
|
"""
|
||||||
|
items = []
|
||||||
|
j = start_idx + 1
|
||||||
|
while j < len(lines):
|
||||||
|
l = lines[j]
|
||||||
|
# 匹配缩进的列表项(至少一个空格或制表符开头,然后 - item)
|
||||||
|
m = re.match(r'^[ \t]+-\s*(.+?)\s*$', l)
|
||||||
|
if m:
|
||||||
|
val = m.group(1).strip()
|
||||||
|
if val:
|
||||||
|
items.append(val)
|
||||||
|
j += 1
|
||||||
|
continue
|
||||||
|
# 如果是新的顶层 bullet(未缩进的 - Something)或者标题、空行,说明离开该段
|
||||||
|
if re.match(r'^\s*-\s*\S', l) or re.match(r'^\s*##\s+', l) or l.strip() == '':
|
||||||
|
break
|
||||||
|
# 其它普通行也视为离开(安全策略)
|
||||||
|
break
|
||||||
|
return items
|
||||||
|
|
||||||
def _parse_edit(file_path: str, _id: str, source_path: str) -> str:
|
def _parse_edit(file_path: str, _id: str, source_path: str) -> str:
|
||||||
text = Path(file_path).read_text(encoding='utf-8')
|
text = Path(file_path).read_text(encoding='utf-8')
|
||||||
# 解析语言(不强制需要)
|
|
||||||
# 解析代码块内容
|
# 解析代码块内容(第一个 code block)
|
||||||
code_match = re.search(r"```(?:\[[^\]]*\]|[A-Za-z0-9_+\-]*)\s*\r?\n([\s\S]*?)```", text)
|
code_match = re.search(r"```(?:\[[^\]]*\]|[A-Za-z0-9_+\-]*)\s*\r?\n([\s\S]*?)```", text)
|
||||||
content = (code_match.group(1) if code_match else '').strip()
|
content = (code_match.group(1) if code_match else '').strip()
|
||||||
# tags
|
|
||||||
tag_lines = re.findall(r"^-\s+(.*)$", text, flags=re.M)
|
|
||||||
# 在 '- Tags' 之后的两级缩进项
|
|
||||||
tags_section = False
|
|
||||||
tags = []
|
|
||||||
for line in text.splitlines():
|
|
||||||
if re.match(r"^-\s*Tags\s*$", line):
|
|
||||||
tags_section = True
|
|
||||||
continue
|
|
||||||
if tags_section:
|
|
||||||
m = re.match(r"^\s*-\s*(.*)$", line)
|
|
||||||
if m:
|
|
||||||
val = m.group(1).strip()
|
|
||||||
if val:
|
|
||||||
tags.append(val)
|
|
||||||
else:
|
|
||||||
# 离开 tags 段
|
|
||||||
tags_section = False
|
|
||||||
# 到 Description 再退出
|
|
||||||
if re.match(r"^-\s*Description\s*$", line):
|
|
||||||
tags_section = False
|
|
||||||
|
|
||||||
desc_match = re.search(r"-\s*Description\s*\n\s*-\s*(.*)", text)
|
lines = text.splitlines()
|
||||||
description = (desc_match.group(1) if desc_match else '').strip()
|
|
||||||
|
tags = []
|
||||||
|
description_lines = []
|
||||||
|
|
||||||
|
# 定位 Tags 段并收集缩进子项
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if re.match(r'^\s*-\s*Tags\s*$', line):
|
||||||
|
tags = _collect_indented_list(lines, i)
|
||||||
|
break
|
||||||
|
|
||||||
|
# 定位 Description 段并收集缩进子项(支持多行)
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if re.match(r'^\s*-\s*Description\s*$', line):
|
||||||
|
description_lines = _collect_indented_list(lines, i)
|
||||||
|
break
|
||||||
|
|
||||||
|
description = ' '.join(description_lines).strip()
|
||||||
|
|
||||||
entity = {
|
entity = {
|
||||||
"id": _id,
|
"id": _id,
|
||||||
@@ -177,6 +215,7 @@ def _parse_edit(file_path: str, _id: str, source_path: str) -> str:
|
|||||||
return json.dumps(entity, ensure_ascii=False)
|
return json.dumps(entity, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _create_tmp(content: str) -> str:
|
def _create_tmp(content: str) -> str:
|
||||||
# 创建临时文件,并写入template_path对应的文件中的内容,最终返回临时文件的路径
|
# 创建临时文件,并写入template_path对应的文件中的内容,最终返回临时文件的路径
|
||||||
# 临时文件路径固定为/tmp/<随机字符串>.md
|
# 临时文件路径固定为/tmp/<随机字符串>.md
|
||||||
@@ -286,11 +325,11 @@ def edit_and_copy(path: str, id: str) -> ActionResult:
|
|||||||
|
|
||||||
def edit(path: str, id: str) -> ActionResult:
|
def edit(path: str, id: str) -> ActionResult:
|
||||||
tmp_path = _create_tmp(template_edit)
|
tmp_path = _create_tmp(template_edit)
|
||||||
primary_hash = _calculate_file_sha256(path)
|
|
||||||
try:
|
try:
|
||||||
_prefill_edit(tmp_path, path, id)
|
_prefill_edit(tmp_path, path, id)
|
||||||
|
primary_hash = _calculate_file_sha256(tmp_path)
|
||||||
_open_with_nvim(tmp_path)
|
_open_with_nvim(tmp_path)
|
||||||
new_hash = _calculate_file_sha256(path)
|
new_hash = _calculate_file_sha256(tmp_path)
|
||||||
if primary_hash == new_hash:
|
if primary_hash == new_hash:
|
||||||
return ActionResult(True, "文件未修改")
|
return ActionResult(True, "文件未修改")
|
||||||
edit_json = _parse_edit(tmp_path, id, path)
|
edit_json = _parse_edit(tmp_path, id, path)
|
||||||
@@ -328,7 +367,5 @@ def add() -> ActionResult:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
tmp_path = _create_tmp(template_add)
|
print(_parse_edit("/home/slhaf/Projects/Projects/CodeSnippet/test/testaaa.md", "111test", "111test"))
|
||||||
_open_with_nvim(tmp_path)
|
|
||||||
add_json = _parse_add(tmp_path)
|
|
||||||
print(add_json)
|
|
||||||
|
|||||||
12
test/testaaa.md
Normal file
12
test/testaaa.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
## Snippet
|
||||||
|
|
||||||
|
```test
|
||||||
|
Testaaa
|
||||||
|
```
|
||||||
|
|
||||||
|
## MetaData
|
||||||
|
|
||||||
|
- Tags
|
||||||
|
- Test
|
||||||
|
- Description
|
||||||
|
- 测试代码片段
|
||||||
Reference in New Issue
Block a user