Repository: ajalt/clikt (kotlin)

Issue:
Argfiles not supported in Clikt library version 5.0 or higher
The implementation of argument files (argfiles) fails when using Clikt library version 5.0 or higher. The application throws an error:
got unexpected extra argument (@src/test/resources/cliargs.arg)

This issue occurs when trying to parse arguments from a file. The feature works correctly with Clikt versions below 5.0. The bug can be reproduced easily by switching to Clikt version 5.0 or higher and making a minor adjustment to the import statement.

Steps to Reproduce:
1. Use Clikt library version 5.0 or higher.
2. Provide an argument file (e.g., @src/test/resources/cliargs.arg).
3. Update the import statement if necessary to match Clikt 5.0 syntax.
4. Run the application.

Expected Behavior:
The argument file should be parsed correctly, as it works with Clikt versions below 5.0.

Actual Behavior:
The application throws an error indicating an unexpected extra argument.

Environment:
- Clikt version: 5.0 or higher
- Operating System: [Specify OS]
- Java/Kotlin version: [Specify version if relevant]

Documentation: https://ajalt.github.io/clikt/advanced/#command-line-argument-files-argfiles

Attachments:
- Zip file containing relevant test cases and configurations: [CliktArgfiles.zip](https://github.com/user-attachments/files/18505787/CliktArgfiles.zip)

Pull request description:
Fixes #570

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e7f03d2e..f38eb280 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,16 @@
 # Changelog
 
 ## Unreleased
+### Fixed
+- Fixed `@argfiles` not being expanded when specified after a subcommand ([#570](https://github.com/ajalt/clikt/pull/570))
+
 ## 5.0.2
 ### Changed
 - Update Kotlin to 2.1.0
 
 ## 5.0.1
 ### Added
-- Added completion commands for suspending and chained commands.  ([#553](https://github.com/ajalt/clikt/pull/553))
+- Added completion commands for suspending and chained commands. ([#553](https://github.com/ajalt/clikt/pull/553))
 - Added no-op suspending commands. ([#554](https://github.com/ajalt/clikt/pull/554))
 
 ### Changed
diff --git a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt
index 5241ca22..7dc391a7 100644
--- a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt
+++ b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt
@@ -317,7 +317,7 @@ class Context private constructor(
          *
          * The block should throw [FileNotFound] if the given `filename` cannot be read.
          */
-        var readArgumentFile: ((filename: String) -> String)? = null
+        var readArgumentFile: ((filename: String) -> String)? = parent?.readArgumentFile
 
         @Suppress("unused")
         @Deprecated("Renamed to readArgumentFile", ReplaceWith("readArgumentFile"))


Test patch:
diff --git a/test/src/commonTest/kotlin/com/github/ajalt/clikt/parsers/AtFileTest.kt b/test/src/commonTest/kotlin/com/github/ajalt/clikt/parsers/AtFileTest.kt
index 707f8248..98baf02d 100644
--- a/test/src/commonTest/kotlin/com/github/ajalt/clikt/parsers/AtFileTest.kt
+++ b/test/src/commonTest/kotlin/com/github/ajalt/clikt/parsers/AtFileTest.kt
@@ -3,8 +3,10 @@ package com.github.ajalt.clikt.parsers
 import com.github.ajalt.clikt.core.CliktCommand
 import com.github.ajalt.clikt.core.UsageError
 import com.github.ajalt.clikt.core.context
+import com.github.ajalt.clikt.core.subcommands
 import com.github.ajalt.clikt.parameters.arguments.argument
 import com.github.ajalt.clikt.parameters.arguments.multiple
+import com.github.ajalt.clikt.parameters.options.flag
 import com.github.ajalt.clikt.parameters.options.option
 import com.github.ajalt.clikt.testing.TestCommand
 import com.github.ajalt.clikt.testing.parse
@@ -151,6 +153,21 @@ class AtFileTest {
         C(false).withAtFiles("baz" to "bar").parse("foo @baz")
     }
 
+    @Test
+    @JsName("atfile_after_subcommand")
+    fun `atfile after subcommand`() {
+        class C: TestCommand() {
+            val o by option().flag()
+
+            override fun run_() {
+                o shouldBe true
+            }
+        }
+
+        TestCommand().subcommands(C())
+            .withAtFiles("f" to "--o").parse("c @f")
+    }
+
     @Test
     @JsName("disabling_atfile")
     fun `disabling atfile`() {