fix: recognise Final Draft files by their content

load() chose the parser from the extension alone, so a .txt that is
really FDX was parsed as Fountain. The .fdx extension still wins, and
other names are sniffed for the FinalDraft root element.
This commit is contained in:
Kharec committed 2026-10-15 17:58:46 +02:00
1 parent 6622203506
commit 764c9d4dc3
2 files changed
+13 -1

No files matched your search

+2
View File
@@ -17,6 +17,8 @@ version is in the `VERSION` file.
- `plotzilla new-script.fountain` opens a new script that will be saved to that file,
instead of an untitled document that forgot the name it was given.
- A Final Draft file named `.txt` (or anything but `.fdx`) is recognised by its
content and opened as FDX, not parsed as Fountain.
- The unsaved-changes marker is now updated atomically: an edit landing while a save
finished could make the close confirmation unreliable.
- Saving is now durable: the file is synced to disk before it replaces the old one (a
+11 -1
View File
@@ -118,7 +118,7 @@ func (a *App) load(path string) (*OpenResult, error) {
return nil, err
}
var doc *screenplay.Document
if strings.EqualFold(filepath.Ext(path), ".fdx") {
if isFDX(path, data) {
if doc, err = fdx.Read(bytes.NewReader(data)); err != nil {
return nil, err
}
@@ -128,6 +128,16 @@ func (a *App) load(path string) (*OpenResult, error) {
return &OpenResult{Path: path, Document: doc}, nil
}
// isFDX reports whether a file is a Final Draft one: the extension says
// so, or its content does — a ".txt" export of Final Draft is still FDX.
func isFDX(path string, data []byte) bool {
if strings.EqualFold(filepath.Ext(path), ".fdx") {
return true
}
head := strings.TrimPrefix(string(data[:min(len(data), 512)]), "\ufeff")
return strings.Contains(head, "<FinalDraft")
}
// Save writes the document to path, asking for one when empty. It returns
// the path written, or "" if the user cancelled.
func (a *App) Save(doc screenplay.Document, path string) (string, error) {