feat(fava): Specify default-file in options

I made a patch for fava, open at https://github.com/beancount/fava/pull/1833,
which makes default files able to be specified as an argument rather
than by placing the default-file directive in the default file. This is
a lot cleaner for us, as this was the only line that we needed to inject
into our newly-created ledgers

Additionally, this patch makes default files be the target for added
entries, which allows us to use the "+" button and will also be required
for importers, both of which previously attempted to insert entries in
the read-only settings file

Change-Id: I49dd803941d8c855eeecb274bd4973a42283c17f
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/804
Reviewed-by: Skyler Grey <minion@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/modules/nixos/clicks/services/fava/default.nix b/modules/nixos/clicks/services/fava/default.nix
index fb707fd..73cab36 100644
--- a/modules/nixos/clicks/services/fava/default.nix
+++ b/modules/nixos/clicks/services/fava/default.nix
@@ -42,7 +42,6 @@
             example = {
               invert-income-liabilities-equity = true;
             };
-            default = {};
           };
           beancountExtraOptions = lib.mkOption {
             type = lib.types.attrsOf lib.types.str;
@@ -75,6 +74,7 @@
         };
         config = {
           beancountExtraOptions.title = lib.mkDefault submodule.config.name;
+          favaExtraOptions.default-file = lib.mkDefault submodule.config.mainFile;
 
           configFile = builtins.toString (let
             generateFavaOption = name: value:
@@ -171,7 +171,7 @@
       in ''
         ${pkgs.coreutils}/bin/mkdir -p "$(${pkgs.coreutils}/bin/dirname "${data.mainFile}")"
         if [ ! -f "${data.mainFile}" ]; then
-          ${pkgs.coreutils}/bin/echo '1970-01-01 custom "fava-option" "default-file"' >> ${data.mainFile}
+          touch ${data.mainFile}
         fi
       '';
 
diff --git a/overlays/fava/1838-default-file-improvements.patch b/overlays/fava/1838-default-file-improvements.patch
new file mode 100644
index 0000000..388be10
--- /dev/null
+++ b/overlays/fava/1838-default-file-improvements.patch
@@ -0,0 +1,126 @@
+From 87af8b9b6f14beaade6e8d5130d062d2198ee5d9 Mon Sep 17 00:00:00 2001
+From: Skyler Grey <sky@a.starrysky.fyi>
+Date: Thu, 18 Jul 2024 20:24:24 +0000
+Subject: [PATCH 1/2] fix!: Respect default-file when inserting entries
+
+It's a common point of confusion that default-file does not set the
+default file for insertions. This patch brings the behavior into line
+with people's expectations.
+
+BREAKING-CHANGE: If you are using default-file and expecting entries to be inserted to your main file, this will no longer happen
+Fixes: beancount/fava#882
+Refs: beancount/fava#1698, beancount/fava#822
+---
+ src/fava/core/file.py    | 5 ++++-
+ src/fava/help/options.md | 2 +-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/fava/core/file.py b/src/fava/core/file.py
+index e76b7ffb9..d225a2497 100644
+--- a/src/fava/core/file.py
++++ b/src/fava/core/file.py
+@@ -233,7 +233,10 @@ def insert_entries(self, entries: list[Directive]) -> None:
+             for entry in sorted(entries, key=_incomplete_sortkey):
+                 path, updated_insert_options = insert_entry(
+                     entry,
+-                    self.ledger.beancount_file_path,
++                    (
++                        self.ledger.fava_options.default_file
++                        or self.ledger.beancount_file_path
++                    ),
+                     insert_options=fava_options.insert_entry,
+                     currency_column=fava_options.currency_column,
+                     indent=fava_options.indent,
+diff --git a/src/fava/help/options.md b/src/fava/help/options.md
+index 22361dcec..dbef9eb23 100644
+--- a/src/fava/help/options.md
++++ b/src/fava/help/options.md
+@@ -113,7 +113,7 @@ a transaction, the account of the last posting is used) is matched against all
+ of the matching options before the entry date. If the entry is a Transaction and
+ no `insert-entry` option matches the account of the last posting the account of
+ the second to last posting and so on will be tried. If no `insert-entry` option
+-matches or none is given, the entry will be inserted at the end of the main
++matches or none is given, the entry will be inserted at the end of the default
+ file.
+ 
+ ---
+
+From 3ff9ec604d9f6d16b4aa88107183a597f5e0c833 Mon Sep 17 00:00:00 2001
+From: Skyler Grey <sky@a.starrysky.fyi>
+Date: Thu, 18 Jul 2024 20:41:55 +0000
+Subject: [PATCH 2/2] feat: Allow specifying the filename to default-file
+
+I autogenerate some fava config, and one option I'd like to specify is
+the default file.
+
+Unfortunately, this previously had to be specified in the file which
+would become the default file, leading to a messy and fragile setup in
+which my (readonly) configuration file would become the default if the
+magical "default-file" line was ever removed from the user-editable
+config.
+
+This feature allows existing semantics around default-file to continue,
+while also providing the ability to set it in some other file if the
+existing options are unsuitable.
+---
+ src/fava/core/fava_options.py   | 9 +++++++--
+ src/fava/help/options.md        | 4 ++--
+ tests/test_core_fava_options.py | 2 ++
+ 3 files changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/src/fava/core/fava_options.py b/src/fava/core/fava_options.py
+index 462ea29d5..23217da2b 100644
+--- a/src/fava/core/fava_options.py
++++ b/src/fava/core/fava_options.py
+@@ -119,12 +119,17 @@ def parse_option_custom_entry(  # noqa: PLR0912
+     if key not in All_OPTS:
+         raise UnknownOptionError(key)
+ 
++    value = entry.values[1].value if len(entry.values) > 1 else None
++
+     if key == "default_file":
+-        filename, _lineno = get_position(entry)
++        if value is None:
++            filename, _lineno = get_position(entry)
++        else:
++            filename = value
++
+         options.default_file = filename
+         return
+ 
+-    value = entry.values[1].value
+     if not isinstance(value, str):
+         raise NotAStringOptionError(key)
+ 
+diff --git a/src/fava/help/options.md b/src/fava/help/options.md
+index dbef9eb23..968730620 100644
+--- a/src/fava/help/options.md
++++ b/src/fava/help/options.md
+@@ -50,8 +50,8 @@ locale `en_IN` the number `1111111.33` will be rendered `11,11,111.33`,
+ ## `default-file`
+ 
+ Use this option to specify a default file for the editor to open. This option
+-takes no value, the file the custom entry is in will be used as the default. If
+-this option is not specified, Fava opens the main file by default.
++may optionally take a value of a filename to be the default. If you don't
++provide a filename, the file this custom option is in is used.
+ 
+ ---
+ 
+diff --git a/tests/test_core_fava_options.py b/tests/test_core_fava_options.py
+index 03206e6ad..9ed1e5bec 100644
+--- a/tests/test_core_fava_options.py
++++ b/tests/test_core_fava_options.py
+@@ -27,6 +27,7 @@ def test_fava_options(load_doc_custom_entries: list[Custom]) -> None:
+     2016-04-14 custom "fava-option" "collapse_pattern" "(invalid"
+     2016-04-14 custom "fava-option" "fiscal-year-end" "01-11"
+     2016-04-14 custom "fava-option" "conversion-currencies" "USD EUR HOOLI"
++    2016-06-14 custom "fava-option" "default-file" "/some/file/name"
+     """
+ 
+     options, errors = parse_options(load_doc_custom_entries)
+@@ -50,3 +51,4 @@ def test_fava_options(load_doc_custom_entries: list[Custom]) -> None:
+     assert options.collapse_pattern == [re.compile("Account:Name")]
+     assert options.fiscal_year_end == FiscalYearEnd(1, 11)
+     assert options.conversion_currencies == ("USD", "EUR", "HOOLI")
++    assert options.default_file == "/some/file/name"
diff --git a/overlays/fava/default.nix b/overlays/fava/default.nix
index 1a9d549..a847886 100644
--- a/overlays/fava/default.nix
+++ b/overlays/fava/default.nix
@@ -19,6 +19,7 @@
 
     patches = (prevAttrs.patches or []) ++ [
       ./1833-respect-ordering.patch
+      ./1838-default-file-improvements.patch
     ];
   });
 }