diff --git a/bin/test_io.py b/bin/test_io.py index 364765a3..3e5dcadd 100644 --- a/bin/test_io.py +++ b/bin/test_io.py @@ -13,35 +13,25 @@ import manuskript.data as data path = os.path.join(sys.path[1], "sample-projects/book-of-acts") -#project = data.Project(path + ".msk") -#project.load() +project = data.Project(path + ".msk") +project.load() -#settings = project.settings +for item in project.outline.all(): + print(str(item.title) + " " + str(item.goal)) -#print(settings.properties) +settings = project.settings -#plots = project.plots +print(settings.properties) -#revs = project.revisions +plots = project.plots -#for status in project.statuses: -# print("--" + str(status)) +revs = project.revisions + +for status in project.statuses: + print("--" + str(status)) #settings.set("saveToZip", True) #project.save() #settings.set("saveToZip", False) #project.save() - -mmd = io.MmdFile(path + "/outline/0-Jerusalem/0-Chapter_1/0-Introduction.md") - -meta, _ = mmd.loadMMD() - -print(meta) - -meta, body = mmd.load() - -print(meta) -print(body) - -mmd.save((meta, body)) diff --git a/manuskript/data/__init__.py b/manuskript/data/__init__.py index 01591ff4..526a9d5d 100644 --- a/manuskript/data/__init__.py +++ b/manuskript/data/__init__.py @@ -3,6 +3,8 @@ from manuskript.data.plots import Plots, PlotLine, PlotStep from manuskript.data.project import Project +from manuskript.data.goal import GoalKind, Goal +from manuskript.data.outline import Outline, OutlineFolder, OutlineText from manuskript.data.revisions import Revisions from manuskript.data.settings import Settings from manuskript.data.status import StatusHost, Status diff --git a/manuskript/data/goal.py b/manuskript/data/goal.py new file mode 100644 index 00000000..4a406f6f --- /dev/null +++ b/manuskript/data/goal.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# --!-- coding: utf8 --!-- + +from enum import Enum, unique + + +@unique +class GoalKind(Enum): + WORDS = 0 + CHARACTERS = 1 + + +class Goal: + + def __init__(self, value: int = 0, kind: GoalKind = GoalKind.WORDS): + self.value = 0 + self.kind = kind + + def __str__(self): + return str(self.value) + " " + self.kind.name.lower() + + @classmethod + def parse(cls, string: str): + if string is None: + return None + + parts = string.split(" ") + + try: + value = int(parts[0]) + kind = GoalKind[parts[1].upper()] if len(parts) > 1 else GoalKind.WORDS + except ValueError: + return None + + return Goal(value, kind) diff --git a/manuskript/data/outline.py b/manuskript/data/outline.py new file mode 100644 index 00000000..c2509d76 --- /dev/null +++ b/manuskript/data/outline.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python +# --!-- coding: utf8 --!-- + +import os + +from enum import Enum, unique +from manuskript.data.goal import Goal +from manuskript.data.unique_id import UniqueIDHost, UniqueID +from manuskript.io.mmdFile import MmdFile + + +@unique +class OutlineState(Enum): + UNDEFINED = 0, + OPTIMIZED = 1, + COMPLETE = 2 + + +class OutlineItem: + + def __init__(self, path, outline): + self.file = MmdFile(path) + self.outline = outline + self.state = OutlineState.UNDEFINED + + self.title = "" + self.UID = None + self.type = "" + self.summarySentence = None + self.summaryFull = None + self.POV = None + self.notes = None + self.label = None + self.status = None + self.compile = True + self.goal = None + + @classmethod + def loadMetadata(cls, item, metadata: dict): + ID = metadata.get("ID") + + if ID is None: + return + + item.UID = item.outline.host.loadID(int(ID)) + item.title = metadata.get("title", None) + item.type = metadata.get("type", "md") + item.summarySentence = metadata.get("summarySentence", None) + item.summaryFull = metadata.get("summaryFull", None) + item.POV = metadata.get("POV", None) + item.notes = metadata.get("notes", None) + item.label = metadata.get("label", None) + item.status = metadata.get("status", None) + item.compile = metadata.get("compile") + item.goal = Goal.parse(metadata.get("setGoal", None)) + + @classmethod + def saveMetadata(cls, item): + metadata = dict() + + if item.UID is None: + return metadata + + metadata["ID"] = str(item.UID.value) + metadata["title"] = item.title + metadata["type"] = item.type + metadata["summarySentence"] = item.summarySentence + metadata["summaryFull"] = item.summaryFull + metadata["POV"] = item.POV + metadata["notes"] = item.notes + metadata["label"] = item.label + metadata["status"] = item.status + metadata["compile"] = item.compile + metadata["setGoal"] = str(item.goal) + + return metadata + + def load(self, optimized: bool = True): + raise IOError('Loading undefined!') + + def save(self): + raise IOError('Saving undefined!') + + +class OutlineText(OutlineItem): + + def __init__(self, path, outline): + OutlineItem.__init__(self, path, outline) + + self.text = "" + + def load(self, optimized: bool = True): + metadata, body = self.file.loadMMD(optimized) + OutlineItem.loadMetadata(self, metadata) + + if not optimized: + self.text = body + self.state = OutlineState.COMPLETE + elif self.state == OutlineState.UNDEFINED: + self.state = OutlineState.OPTIMIZED + + def save(self): + if self.state == OutlineState.OPTIMIZED: + self.load(False) + + metadata = OutlineItem.saveMetadata(self) + self.file.save((metadata, self.text)) + + +class OutlineFolder(OutlineItem): + + def __init__(self, path, outline): + self.dir_path = path + self.items = list() + + OutlineItem.__init__(self, os.path.join(self.dir_path, "folder.txt"), outline) + + def __iter__(self): + return self.items.__iter__() + + @classmethod + def loadItems(cls, outline, folder, recursive: bool = True): + folder.items.clear() + + names = os.listdir(folder.dir_path) + names.remove("folder.txt") + + for name in names: + path = os.path.join(folder.dir_path, name) + + if os.path.isdir(path): + item = OutlineFolder(path, outline) + else: + item = OutlineText(path, outline) + + try: + item.load() + except FileNotFoundError: + continue + + folder.items.append(item) + + if recursive: + for item in folder.items: + if type(item) is OutlineFolder: + cls.loadItems(outline, item, recursive) + + def load(self, _: bool = True): + metadata, _ = self.file.loadMMD(True) + OutlineItem.loadMetadata(self, metadata) + self.state = OutlineState.COMPLETE + + @classmethod + def saveItems(cls, folder, recursive: bool = True): + for item in folder.items: + item.save() + + if recursive: + for item in folder.items: + if type(item) is OutlineFolder: + cls.saveItems(item, recursive) + + def save(self): + self.type = "folder" + metadata = OutlineItem.saveMetadata(self) + self.file.save((metadata, "")) + + +class Outline: + + def __init__(self, path): + self.dir_path = os.path.join(path, "outline") + self.host = UniqueIDHost() + self.items = list() + + def __iter__(self): + return self.items.__iter__() + + def all(self): + result = list() + queue = list(self.items) + + while len(queue) > 0: + item = queue.pop() + + if type(item) is OutlineFolder: + for child in item: + queue.append(child) + + result.append(item) + + return result + + def load(self): + self.items.clear() + + for name in os.listdir(self.dir_path): + path = os.path.join(self.dir_path, name) + + if os.path.isdir(path): + item = OutlineFolder(path, self) + else: + item = OutlineText(path, self) + + try: + item.load() + except FileNotFoundError: + continue + + self.items.append(item) + + for item in self.items: + if type(item) is OutlineFolder: + OutlineFolder.loadItems(self, item, True) + + def save(self): + for item in self.items: + item.save() + + for item in self.items: + if type(item) is OutlineFolder: + OutlineFolder.saveItems(item, True) diff --git a/manuskript/data/project.py b/manuskript/data/project.py index d5320ae2..c7211535 100644 --- a/manuskript/data/project.py +++ b/manuskript/data/project.py @@ -2,10 +2,12 @@ # --!-- coding: utf8 --!-- from zipfile import BadZipFile -from manuskript.data.plots import Plots -from manuskript.data.revisions import Revisions -from manuskript.data.settings import Settings +from manuskript.data.summary import Summary from manuskript.data.status import StatusHost +from manuskript.data.settings import Settings +from manuskript.data.plots import Plots +from manuskript.data.outline import Outline +from manuskript.data.revisions import Revisions from manuskript.io.mskFile import MskFile @@ -14,9 +16,11 @@ class Project: def __init__(self, path): self.file = MskFile(path) + self.summary = Summary(self.file.dir_path) self.statuses = StatusHost(self.file.dir_path) self.settings = Settings(self.file.dir_path) self.plots = Plots(self.file.dir_path) + self.outline = Outline(self.file.dir_path) self.revisions = Revisions(self.file.dir_path) def __del__(self): @@ -30,22 +34,24 @@ class Project: except FileNotFoundError: return + self.summary.load() self.statuses.load() self.settings.load() self.plots.load() + self.outline.load() self.revisions.load() self.file.setZipFile(self.settings.isEnabled("saveToZip")) def save(self): - print("Save project: " + str(self.file.path) + " " + str(self.file.dir_path)) - saveToZip = self.settings.isEnabled("saveToZip") self.file.setZipFile(saveToZip) + self.summary.load() self.statuses.save() self.settings.save() self.plots.save() + self.outline.save() #self.revisions.save() self.file.save(saveToZip) diff --git a/manuskript/data/summary.py b/manuskript/data/summary.py new file mode 100644 index 00000000..05a57723 --- /dev/null +++ b/manuskript/data/summary.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# --!-- coding: utf8 --!-- + +import os + +from manuskript.io.mmdFile import MmdFile + + +class Summary: + + def __init__(self, path): + self.file = MmdFile(os.path.join(path, "summary.txt"), 13) + + self.sentence = None + self.paragraph = None + self.page = None + self.full = None + + def load(self): + metadata, _ = self.file.loadMMD(True) + + self.sentence = metadata.get("Sentence", None) + self.paragraph = metadata.get("Paragraph", None) + self.page = metadata.get("Page", None) + self.full = metadata.get("Full", None) + + def save(self): + metadata = dict() + + metadata["Sentence"] = self.sentence + metadata["Paragraph"] = self.paragraph + metadata["Page"] = self.page + metadata["Full"] = self.full + + self.file.save((metadata, None)) diff --git a/manuskript/io/mmdFile.py b/manuskript/io/mmdFile.py index ed56ef34..1ca4356d 100644 --- a/manuskript/io/mmdFile.py +++ b/manuskript/io/mmdFile.py @@ -8,6 +8,11 @@ from manuskript.io.abstractFile import AbstractFile class MmdFile(AbstractFile): + def __init__(self, path, metaSpacing = 16): + AbstractFile.__init__(self, path) + + self.metaSpacing = metaSpacing + def loadMMD(self, ignoreBody: bool = True): metadata = dict() body = None @@ -34,11 +39,11 @@ class MmdFile(AbstractFile): if not (m is None): metaValue += "\n" + m.group(2) elif line == "\n": - if not (metaKey is None): - metadata[metaKey] = metaValue - break + if not (metaKey is None): + metadata[metaKey] = metaValue + if not ignoreBody: body = file.read() @@ -49,13 +54,16 @@ class MmdFile(AbstractFile): def save(self, content): metadata, body = content - metaSpacing = 0 + metaSpacing = self.metaSpacing for key in metadata.keys(): metaSpacing = max(metaSpacing, len(key) + 2) with open(self.path, 'wt', encoding='utf-8') as file: for (key, value) in metadata.items(): + if value is None: + continue + spacing = metaSpacing - (len(key) + 2) lines = value.split("\n") @@ -64,6 +72,5 @@ class MmdFile(AbstractFile): for line in lines[1:]: file.write(metaSpacing * " " + line + "\n") - file.write("\n") if not (body is None): - file.write(body) + file.write("\n" + body)