修复问题

- 修复了 rofi 前端编辑文件时的填充、提取json信息的问题
- 修复了后端在处理编辑文件请求时,会清空Language信息的问题
This commit is contained in:
2025-10-05 22:33:10 +08:00
parent 2db2c580cb
commit 9a72aad9d2
3 changed files with 112 additions and 58 deletions

View File

@@ -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;
} }

View File

@@ -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
View File

@@ -0,0 +1,12 @@
## Snippet
```test
Testaaa
```
## MetaData
- Tags
- Test
- Description
- 测试代码片段