Repository: pdm-project/pdm (python)

Issue:
`[tool.pdm.options]` is ignored by `pdm --config <somefile> ...`
- [x] I have searched the issue tracker and believe that this is not a duplicate.

**Make sure you run commands with `-v` flag before pasting the output.**

## Steps to reproduce

Start a project with this `pyproject.toml`:
```
[tool.pdm.options]
lock = ["--verbose"]

[project]
name = ""
version = ""
description = ""
authors = []
license = {text = "MIT"}
dependencies = []
requires-python = ">=3.11"
```

Then run `pdm -c /dev/null lock` or `pdm --config /dev/null lock`.

## Actual behavior

<!--A clear and concise description the result of the above steps-->

The `--verbose` option is not applied to `pdm lock`.

## Expected behavior

<!--A clear and concise description of what you expected to happen.-->

It should be equivalent to `pdm lock --verbose`, according to the documentation.

As a workaround, I can use `pdm --config=/dev/null lock`, in which case the `--verbose` does seem to be applied correctly.

## Environment Information

```bash
# Paste the output of `pdm info && pdm info --env` below:
PDM version:
  2.13.0
Python Interpreter:
  /home/darsh/virtualenvs/python3.11/bin/python (3.11)
Project Root:
  /home/darsh/work/pdm-test
Local Packages:
  /home/darsh/work/pdm-test/__pypackages__/3.11
{
  "implementation_name": "cpython",
  "implementation_version": "3.11.9",
  "os_name": "posix",
  "platform_machine": "x86_64",
  "platform_release": "5.15.0-102-generic",
  "platform_system": "Linux",
  "platform_version": "#112~20.04.1-Ubuntu SMP Thu Mar 14 14:28:24 UTC 2024",
  "python_full_version": "3.11.9",
  "platform_python_implementation": "CPython",
  "python_version": "3.11",
  "sys_platform": "linux"
}
```


Pull request description:
fix: `[tool.pdm.options]` is ignored by `pdm --config <somefile> ...`
Fixes #2793

Signed-off-by: Frost Ming <me@frostming.com>

## Pull Request Checklist

- [ ] A news fragment is added in `news/` describing what is new.
- [ ] Test cases added for changed code.

## Describe what you have changed in this PR.


Patch:
diff --git a/news/2793.bugfix.md b/news/2793.bugfix.md
new file mode 100644
index 00000000..e03205b5
--- /dev/null
+++ b/news/2793.bugfix.md
@@ -0,0 +1,1 @@
+Fix a bug that `[tool.pdm.options]` are ignored if `-c/--config CONFIG` is given.
diff --git a/src/pdm/core.py b/src/pdm/core.py
index 3dca4df4..3c5519e6 100644
--- a/src/pdm/core.py
+++ b/src/pdm/core.py
@@ -106,7 +106,6 @@ class Core:
             prog="pdm",
             description=__doc__,
         )
-        self.parser.is_root = True  # type: ignore[attr-defined]
         self.parser.add_argument(
             "-V",
             "--version",
@@ -208,12 +207,31 @@ class Core:
             sys.exit(0)
         command.handle(project, options)
 
+    @staticmethod
+    def get_command(args: list[str]) -> tuple[int, str]:
+        """Get the command name from the arguments"""
+        options_with_values = ("-c", "--config")
+        need_value = False
+        for i, arg in enumerate(args):
+            if arg.startswith("-"):
+                if not arg.startswith(options_with_values):
+                    continue
+                if (arg.startswith("-c") and arg != "-c") or arg.startswith("--config="):
+                    continue
+                need_value = True
+            elif need_value:
+                need_value = False
+                continue
+            else:
+                return i, arg
+        return -1, ""
+
     def _get_cli_args(self, args: list[str], obj: Project | None) -> list[str]:
         project = self.create_project(is_global=False) if obj is None else obj
         if project.is_global:
             return args
         config = project.pyproject.settings.get("options", {})
-        (pos, command) = next(((i, arg) for i, arg in enumerate(args) if not arg.startswith("-")), (-1, None))
+        (pos, command) = self.get_command(args)
         if command and command in config:
             # add args after the command
             args[pos + 1 : pos + 1] = list(config[command])
@@ -238,7 +256,7 @@ class Core:
             # Failed to parse, try to give all to `run` command as shortcut
             # and keep to root script (first non-dashed param) to check existence
             # as soon as the project is parsed
-            root_script = next((arg for arg in args if not arg.startswith("-")), None)
+            _, root_script = self.get_command(args)
             if not root_script:
                 self.parser.error(str(e.__cause__))
             try:


Test patch:
diff --git a/tests/test_project.py b/tests/test_project.py
index 634a070c..60b45fab 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -335,6 +335,10 @@ def test_invoke_pdm_adding_configured_args(project, pdm, mocker):
     parser.assert_called_with(["install", "--no-self", "--no-editable", "--check"])
     pdm(["lock", "--lockfile", "pdm.2.lock"], obj=project)
     parser.assert_called_with(["lock", "--no-cross-platform", "--lockfile", "pdm.2.lock"])
+    pdm(["-c", "/dev/null", "lock"], obj=project)
+    parser.assert_called_with(["-c", "/dev/null", "lock", "--no-cross-platform"])
+    pdm(["--verbose", "add", "requests"], obj=project)
+    parser.assert_called_with(["--verbose", "add", "--no-isolation", "requests"])
 
 
 @pytest.fixture()