mirror of
https://git.srhtnin.garden/sarah/SaraView.git
synced 2026-10-13 18:28:14 +02:00
Added children, siblings, and parents as variables. Also % as for.
This commit is contained in:
1 parent
104198036a
commit
0cd98873e0
2 files changed
+109
-4
No files matched your search
+99
-2
@@ -3,12 +3,13 @@ from __future__ import annotations
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from Core import NormalizeRelativePath, ResolvePath
|
from Core import NormalizeRelativePath, ResolvePath
|
||||||
from Explorer import ClassifyFile, ListDirectory
|
from Explorer import ClassifyFile, ListDirectory, NoteFilePrefix
|
||||||
from Locks import IsPathAccessible
|
from Locks import IsPathAccessible
|
||||||
from Preview import ReadTextFile
|
from Preview import ReadTextFile
|
||||||
|
|
||||||
|
|
||||||
PortalFileTypes = {"markdown", "text"}
|
PortalFileTypes = {"markdown", "text"}
|
||||||
|
LoopSources = ("children", "siblings", "parents")
|
||||||
|
|
||||||
MarkerPattern = re.compile(
|
MarkerPattern = re.compile(
|
||||||
r"\{(?:(?P<CrossPath>[^\s{}']+)\s+)?\*\*\*(?P<CrossName>[^\s*{}]+)"
|
r"\{(?:(?P<CrossPath>[^\s{}']+)\s+)?\*\*\*(?P<CrossName>[^\s*{}]+)"
|
||||||
@@ -19,6 +20,11 @@ MarkerPattern = re.compile(
|
|||||||
r"|\{\*(?P<BlockName>[^\s*{}]+)\}"
|
r"|\{\*(?P<BlockName>[^\s*{}]+)\}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LoopMarkerPattern = re.compile(
|
||||||
|
r"\{(?P<LoopSource>children|siblings|parents)\s+%\s+(?P<LoopVar>[A-Za-z_][A-Za-z0-9_]*)\}"
|
||||||
|
r"|\{(?P<CloseSource>children|siblings|parents)\s+%\}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _LineBounds(Content: str, Position: int) -> tuple[int, int]:
|
def _LineBounds(Content: str, Position: int) -> tuple[int, int]:
|
||||||
LineStart = Content.rfind("\n", 0, Position) + 1
|
LineStart = Content.rfind("\n", 0, Position) + 1
|
||||||
@@ -94,6 +100,95 @@ def _ResolveLocalPortals(Content: str) -> str:
|
|||||||
return "".join(Output)
|
return "".join(Output)
|
||||||
|
|
||||||
|
|
||||||
|
def _ListAccessibleEntryNames(
|
||||||
|
RootName: str, DirectoryRelativePath: str, Username: str, UserGroups: list[str], Exclude: str | None
|
||||||
|
) -> list[str]:
|
||||||
|
if not IsPathAccessible(RootName, DirectoryRelativePath, Username, UserGroups):
|
||||||
|
return []
|
||||||
|
|
||||||
|
try:
|
||||||
|
Entries = ListDirectory(RootName, DirectoryRelativePath, False, False)
|
||||||
|
except (ValueError, NotADirectoryError, FileNotFoundError):
|
||||||
|
return []
|
||||||
|
|
||||||
|
Names: list[str] = []
|
||||||
|
|
||||||
|
for Entry in Entries:
|
||||||
|
if Entry["Name"] == Exclude:
|
||||||
|
continue
|
||||||
|
|
||||||
|
EntryPath = (
|
||||||
|
f"{DirectoryRelativePath}/{Entry['Name']}" if DirectoryRelativePath else Entry["Name"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if IsPathAccessible(RootName, EntryPath, Username, UserGroups):
|
||||||
|
Names.append(Entry["Name"])
|
||||||
|
|
||||||
|
return Names
|
||||||
|
|
||||||
|
|
||||||
|
def _ComputeLoopLists(
|
||||||
|
RootName: str, RelativePath: str, Username: str, UserGroups: list[str]
|
||||||
|
) -> dict[str, list[str]]:
|
||||||
|
FileName = RelativePath.rsplit("/", 1)[-1] if RelativePath else ""
|
||||||
|
ParentDirectory = RelativePath.rsplit("/", 1)[0] if "/" in RelativePath else ""
|
||||||
|
ParentBaseName = ParentDirectory.rsplit("/", 1)[-1] if ParentDirectory else ""
|
||||||
|
|
||||||
|
IsDirectoryNote = FileName.startswith(f"{NoteFilePrefix}{ParentBaseName}.")
|
||||||
|
|
||||||
|
Children = (
|
||||||
|
_ListAccessibleEntryNames(RootName, ParentDirectory, Username, UserGroups, FileName)
|
||||||
|
if IsDirectoryNote
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
Siblings = _ListAccessibleEntryNames(RootName, ParentDirectory, Username, UserGroups, FileName)
|
||||||
|
Parents = [Segment for Segment in ParentDirectory.split("/") if Segment]
|
||||||
|
|
||||||
|
return {"children": Children, "siblings": Siblings, "parents": Parents}
|
||||||
|
|
||||||
|
|
||||||
|
def _ResolveLoops(Content: str, Lists: dict[str, list[str]]) -> str:
|
||||||
|
Matches = list(LoopMarkerPattern.finditer(Content))
|
||||||
|
Output: list[str] = []
|
||||||
|
Cursor = 0
|
||||||
|
Index = 0
|
||||||
|
|
||||||
|
while Index < len(Matches):
|
||||||
|
Match = Matches[Index]
|
||||||
|
|
||||||
|
if not Match.group("LoopSource"):
|
||||||
|
Index += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
Source = Match.group("LoopSource")
|
||||||
|
LoopVar = Match.group("LoopVar")
|
||||||
|
|
||||||
|
CloseMatch = None
|
||||||
|
for Candidate in Matches[Index + 1 :]:
|
||||||
|
if Candidate.group("CloseSource") == Source:
|
||||||
|
CloseMatch = Candidate
|
||||||
|
break
|
||||||
|
|
||||||
|
BodyEnd = CloseMatch.start() if CloseMatch is not None else len(Content)
|
||||||
|
BodyTemplate = Content[Match.end() : BodyEnd]
|
||||||
|
Items = Lists.get(Source, [])
|
||||||
|
VariablePattern = re.compile(rf"%{re.escape(LoopVar)}\b")
|
||||||
|
|
||||||
|
Rendered = "\n".join(VariablePattern.sub(Item, BodyTemplate) for Item in Items)
|
||||||
|
|
||||||
|
Output.append(Content[Cursor : Match.start()])
|
||||||
|
Output.append(Rendered)
|
||||||
|
Cursor = CloseMatch.end() if CloseMatch is not None else len(Content)
|
||||||
|
|
||||||
|
if CloseMatch is not None:
|
||||||
|
Index = Matches.index(CloseMatch) + 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
Output.append(Content[Cursor:])
|
||||||
|
return "".join(Output)
|
||||||
|
|
||||||
|
|
||||||
def _ReadAccessiblePortalSource(
|
def _ReadAccessiblePortalSource(
|
||||||
RootName: str, RelativePath: str, Username: str, UserGroups: list[str]
|
RootName: str, RelativePath: str, Username: str, UserGroups: list[str]
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
@@ -224,7 +319,9 @@ def _ResolveLineNumberReference(
|
|||||||
def ResolvePortals(
|
def ResolvePortals(
|
||||||
RootName: str, RelativePath: str, Content: str, Username: str, UserGroups: list[str]
|
RootName: str, RelativePath: str, Content: str, Username: str, UserGroups: list[str]
|
||||||
) -> str:
|
) -> str:
|
||||||
LocallyResolved = _ResolveLocalPortals(Content)
|
LoopLists = _ComputeLoopLists(RootName, RelativePath, Username, UserGroups)
|
||||||
|
WithLoopsResolved = _ResolveLoops(Content, LoopLists)
|
||||||
|
LocallyResolved = _ResolveLocalPortals(WithLoopsResolved)
|
||||||
RefererDirectory = RelativePath.rsplit("/", 1)[0] if "/" in RelativePath else ""
|
RefererDirectory = RelativePath.rsplit("/", 1)[0] if "/" in RelativePath else ""
|
||||||
|
|
||||||
Matches = list(MarkerPattern.finditer(LocallyResolved))
|
Matches = list(MarkerPattern.finditer(LocallyResolved))
|
||||||
|
|||||||
+10
-2
@@ -239,7 +239,15 @@ export default function App() {
|
|||||||
const Created = await EnsureDirectoryNote(ActiveRoot, DirectoryPath);
|
const Created = await EnsureDirectoryNote(ActiveRoot, DirectoryPath);
|
||||||
HandleSelectDirectoryNote(DirectoryPath, Created.Name, Created.FileType);
|
HandleSelectDirectoryNote(DirectoryPath, Created.Name, Created.FileType);
|
||||||
} catch (Error) {
|
} catch (Error) {
|
||||||
SetErrorMessage(Error.message);
|
HandleNavigateDirectory(DirectoryPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function HandleBreadcrumbNavigate(Path) {
|
||||||
|
if (!Path) {
|
||||||
|
HandleNavigateDirectory("");
|
||||||
|
} else {
|
||||||
|
OpenDirectoryNote(Path, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +341,7 @@ export default function App() {
|
|||||||
RootName={ActiveRoot}
|
RootName={ActiveRoot}
|
||||||
FilePath={ViewPath}
|
FilePath={ViewPath}
|
||||||
IsDirectory={ViewIsDirectory || Boolean(ViewNoteFilePath)}
|
IsDirectory={ViewIsDirectory || Boolean(ViewNoteFilePath)}
|
||||||
OnNavigate={HandleNavigateDirectory}
|
OnNavigate={HandleBreadcrumbNavigate}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|||||||
Reference in new issue
Block a user