microsoft / vscode-cpptools

Official repository for the Microsoft C/C++ extension for VS Code.
Other
5.45k stars 1.53k forks source link

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

Open zjturner opened 6 years ago

zjturner commented 6 years ago

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.

pieandcakes commented 6 years ago

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.

zjturner commented 6 years ago

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 notifications@github.com 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 .

pieandcakes commented 6 years ago

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.

zjturner commented 6 years ago

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.

pieandcakes commented 6 years ago

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

geajack commented 4 years ago

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

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

chatziko commented 4 years ago

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:

audetto commented 2 years ago

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.

resk8 commented 2 years ago

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

ShadyBoukhary commented 2 years ago

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

ShadyBoukhary commented 2 years ago

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

ShadyBoukhary commented 2 years ago

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

emaglic commented 1 year ago

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 ""
AndrewJRichardson commented 1 year ago

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": []
        }
    ]
JPHutchins commented 1 year ago

@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:

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"
        },
    ]
}
aqnuep commented 11 months ago

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.

Vishwas-Adiga commented 10 months ago

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
  }
]
stewpend0us commented 9 months ago

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

marcelrend commented 7 months ago

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.