vscode-cpptools icon indicating copy to clipboard operation
vscode-cpptools copied to clipboard

Allow "args" to be specified as a single string.

Open zjturner opened this issue 8 years ago • 19 comments

When configuring the launch.json file, it expects args to be an array of strings that are passed to the process, where each item in the array is one argument. This is extremely user-unfriendly when dealing with long command lines. For example, here is my use case.

Problem: I want to debug clang when you run clang-cl.exe /c foo.cpp

Step 1: Run clang-cl.exe /c foo.cpp -###

E:\src\llvmbuild\ninja>bin\clang-cl /c foo.cpp -###
clang version 6.0.0
Target: i686-pc-windows-msvc
Thread model: posix
InstalledDir: E:\src\llvmbuild\ninja\bin
 "E:\\src\\llvmbuild\\ninja\\bin\\clang-cl.exe" "-cc1" "-triple" "i686-pc-windows-msvc19.11.25508" "-emit-obj"
"-mrelax-all" "-mincremental-linker-compatible" "-disable-free" "-main-file-name" "foo.cpp" "-mrelocation-model"
"static" "-mthread-model" "posix" "-mdisable-fp-elim" "-relaxed-aliasing" "-fmath-errno" "-masm-verbose"
"-mconstructor-aliases" "-target-cpu" "pentium4" "-D_MT" "-flto-visibility-public-std" "--dependent-lib=libcmt"
"--dependent-lib=oldnames" "-stack-protector" "2" "-fms-volatile" "-fdiagnostics-format" "msvc"
"-dwarf-column-info" "-debugger-tuning=gdb" "-coverage-notes-file" "E:\\src\\llvmbuild\\ninja\\foo.gcno" "-resource-dir" "E:\\src\\llvmbuild\\ninja\\lib\\clang\\6.0.0"
"-internal-isystem" "E:\\src\\llvmbuild\\ninja\\lib\\clang\\6.0.0\\include"
"-internal-isystem" "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\VC\\Tools\\MSVC\\14.11.25503\\ATLMFC\\include"
"-internal-isystem" "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\VC\\Tools\\MSVC\\14.11.25503\\include"
"-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\include\\um"
"-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.16299.0\\ucrt"
"-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.16299.0\\shared" 
"-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.16299.0\\um"
"-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.16299.0\\winrt"
"-fdeprecated-macro" "-fdebug-compilation-dir" "E:\\src\\llvmbuild\\ninja" "-ferror-limit" "19"
"-fmessage-length" "120" "-fno-use-cxa-atexit" "-fms-extensions" "-fms-compatibility"
"-fms-compatibility-version=19.11.25508" "-std=c++14" "-fdelayed-template-parsing"
"-fobjc-runtime=gcc" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-o" "foo.obj" "-x" "c++" "foo.cpp"

Step 2: Take the resulting command line, and debug that. this is necessary because the original invocation actually spawns a child process whose command line is the second invocation, and it is that child invocation that actually needs to be debugged.

In order for me to do this, I have to manually add commas to this huge list of command line arguments.

Worse, if I change one little option to the original clang-cl.exe this entire line could end up being different, and I have to do this all over again. It would be nice if I could just paste this somewhere as a single string.

In regular VS there is one box where I can just paste this. Even in GDB I can just run gdb against clang-cl.exe and then pass command line arguments as a single string. This is a very big productivity hit for projects that frequently debug processes with long command lines.

zjturner avatar Nov 07 '17 04:11 zjturner

Fastest way I can see would be to do a find and replace of " " with ",".

You can make it all one string but then its passed to the program as one string and many programs don't like it as one string. We offer this option to allow users the flexibility of specifying separate arguments or arguments with spaces in them.

If you want them as one string, you can replace each " with /" and it will pass it as one string with your quotes.

pieandcakes avatar Nov 09 '17 02:11 pieandcakes

The problem with one string is, as you say, it won’t work for cases where arguments contain spaces.

Given that “i have a command line, I need to paste it into a json array” is going to come up repeatedly for many users, what about a Paste Special type command that just does this? Bind it to Ctrl+Shift+V or something. On Wed, Nov 8, 2017 at 6:00 PM Pierson Lee [email protected] wrote:

Fastest way I can see would be to do a find and replace of " " with ",".

You can make it all one string but then its passed to the program as one string and many programs don't like it as one string. We offer this option to allow users the flexibility of specifying separate arguments or arguments with spaces in them.

If you want them as one string, you can replace each " with /" and it will pass it as one string with your quotes.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Microsoft/vscode-cpptools/issues/1210#issuecomment-343023400, or mute the thread https://github.com/notifications/unsubscribe-auth/ALRpSQhca0chdAjsP2Dn2NRb4mokTBwAks5s0ly1gaJpZM4QUPic .

zjturner avatar Nov 09 '17 02:11 zjturner

I added it as a feature request. I assume we can provide a shortcut but this might be more beneficial to ask VS Code itself to have this feature instead of it only being available for the CPP extension.

pieandcakes avatar Nov 09 '17 02:11 pieandcakes

I asked in vscode github and they said to just make an extension. That's about what I expected them to say, but I believe this is useful enough that vscode should support it directly, if not in the larger project in the cpptools extension. Setting a debugging command line is an extremely difficult and awkward thing to do right without it.

zjturner avatar Nov 20 '17 02:11 zjturner

I marked it as a Feature request and we can take a look at what it would take.

pieandcakes avatar Nov 20 '17 18:11 pieandcakes

I'd like this to, so that I can specify the args as an input:

"args": "${input:arguments}"

jack-jjm avatar Jun 27 '20 14:06 jack-jjm

And also as a configuration parameter:

"args": "${config:program_args}"

Not not mention that it's just the canonical way people have been providing program args in shells for decades :smile:

chatziko avatar Jul 04 '20 14:07 chatziko

Has this ever been implemented? Might not work in 100% case, but it will save time to 99% people 99% of the time.

It could be flexible and handle both an array (of string) or a single string.

audetto avatar Jan 14 '22 18:01 audetto

any status on this? having to separate my 20+ args in comas and quotes is really painful.

resk8 avatar Mar 24 '22 14:03 resk8

Been bothered by this for years. Might make my own extension.

ShadyBoukhary avatar Sep 07 '22 20:09 ShadyBoukhary

I'm working on an extension for this at the moment.

ShadyBoukhary avatar Sep 09 '22 18:09 ShadyBoukhary

Done. If anybody is interested @resk8 @zjturner @audetto here's the extension https://marketplace.visualstudio.com/items?itemName=shadyboukhary.paste-as-string-array

ShadyBoukhary avatar Sep 10 '22 00:09 ShadyBoukhary

I found this thread while trying to resolve this multiple args as single string issue with VS Code's debugger for a node project and I found a kind of hacky solution that seems to work for me, perhaps it can work here as well.

I found that the args array always wrapped my string input in a single set of quotes. But by modifying the args line in launch.json to have a closing quote at the start and a closing quote at the end I was able to step out of the quotes altogether and have my input string be added directly as regular bash options.

You end up with an empty set of quotes at the start and end of the output in the Debug Console, but that didn't seem to cause any issues on my end.

// Input value for promptString
--version 1.0 --path ./test

// launch.json
"args": "\" ${input:args} \""

"inputs": [
    {
      "id": "args",
      "description": "Input Args",
      "type": "promptString"
    }
  ]

// Debug Console Output
"C:\Program Files\nodejs\node.exe" .\test.js "" --version 1.0 --path ./test ""

emaglic avatar Apr 13 '23 16:04 emaglic

After experimenting with @emaglic 's solution I noticed something.

The behaviour of "args": "" and "args":[""] are different. Not sure if it is intentional.

If you use a single string no quoutes are added, if you use an array with spaces in any argument then quotes will be added. Tried this with cppvsdbg not tested cppdbg

Example config:

    "configurations": [
            {
                "type": "cppvsdbg",
                "program": "C:\\Program Files\\nodejs\\node.exe",
                "name": "ArgTest",
                "cwd": "${workspaceRoot}",
                "request": "launch",
            }

Array style:

  "args": ["--version 1.0 --path ./test"],
  
  Output:  bad option: --version 1.0 --path ./test

Single string style: It might complain about args not being an array but it will work when run.

   "args":"--version 1.0 --path ./test",
   
   Output:  v20.4.0

I suspect this isn't intended behaviour as it is inconsistent and undocumented. However, It does allow a single string and it does expand variables like ${input:myvar}.

I think a better solution might be to do something like tasks args having the quoting option, but allow us to specify "none" which will stop the adding of quotes.

"tasks": [
        {
            "label": "My Task",
            "type": "shell",
            "command": "echo",
            "args": [ { "quoting": "none", "value": "myArg1 myArg2"}],
            "problemMatcher": []
        }
    ]

AndrewJRichardson avatar Aug 09 '23 16:08 AndrewJRichardson

@pieandcakes

VSCode's launch.json now supports the required feature for non-hacky implementation. The "args" field can either be an array or a string. If it is a string, then it is interpreted as space-separated arguments, allowing launch.json to specify a single "input" that contains 0 or more arguments, rather than an array of inputs that each contain 1 or fewer arguments.

cppdbg does not support this VSCode feature - instead it enforces "args" as an array, requiring verbose hacks to get simple behavior.

Info from VSCode team about support:

  • https://github.com/microsoft/vscode-docs/blob/vnext/release-notes/v1_70.md#javascript-debugging
  • https://github.com/microsoft/vscode-docs/blob/vnext/release-notes/v1_70.md#argscanbeinterpretedbyshell-for-runinterminalrequest

Without this feature, "args" is an array, hard coding 4 possible positional arguments:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "my_program",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/my_program",
            "args": [
                "${input:arg1}",
                "${input:arg2}",
                "${input:arg3}",
                "${input:arg4}",
            ],
        },
    ],
    "inputs": [
        {
            "id": "arg1",
            "type": "promptString",
            "description": "required 1st arg"
        },
        {
            "id": "arg2",
            "type": "promptString",
            "description": "optional 2nd arg"
        },
        {
            "id": "arg3",
            "type": "promptString",
            "description": "optional 3rd arg"
        },
        {
            "id": "arg4",
            "type": "promptString",
            "description": "optional 4th arg"
        }
    ]
}

With this feature, "args" is a string; both config and usage are simple and extensible. The user does not have to come back to the launch.json and add more dummy inputs in case the program being run adds more args. The user does not have to hit enter on dummy prompts just because the program CAN take more args.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "my_program",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/my_program",
            "args": "${input:args}",
        },
    ],
    "inputs": [
        {
            "id": "args",
            "type": "promptString",
            "description": "space separated args"
        },
    ]
}

JPHutchins avatar Sep 02 '23 19:09 JPHutchins

I agree that this is a much needed feature. It would be great to get support for it as it imposes severe limitations on the usability of the launch.json for C++ projects.

aqnuep avatar Oct 12 '23 16:10 aqnuep

A workaround for now would be to pass the arguments to gdb directly instead of using the launch config's args field, like so:

"setupCommands": [
  {
    "description": "Set command line arguments",
    "text": "-gdb-set args ${input:commandLineArgs}",
    "ignoreFailures": true
  }
]

Or if using static text,

"setupCommands": [
  {
    "description": "Set command line arguments",
    "text": "-gdb-set args arg1 arg2 arg3 arg4",
    "ignoreFailures": true
  }
]

Vishwas-Adiga avatar Oct 27 '23 01:10 Vishwas-Adiga

A workaround for now would be to pass the arguments to gdb directly instead of using the launch config's args field, like so:

"setupCommands": [
  {
    "description": "Set command line arguments",
    "text": "-gdb-set args ${input:commandLineArgs}",
    "ignoreFailures": true
  }
]

Or if using static text,

"setupCommands": [
  {
    "description": "Set command line arguments",
    "text": "-gdb-set args arg1 arg2 arg3 arg4",
    "ignoreFailures": true
  }
]

this seems like the answer to me! not a workaround

stewpend0us avatar Dec 07 '23 17:12 stewpend0us

I'd like this to, so that I can specify the args as an input:

"args": "${input:arguments}"

I just tried this in version 1.85.1 and it's working now! Make sure you provide a single string with all your args and don't use an array.

marcelrend avatar Feb 07 '24 09:02 marcelrend