svaante / dape

Debug Adapter Protocol for Emacs
GNU General Public License v3.0
501 stars 34 forks source link

Suggestion: New command dape-info-variable-value-copy #168

Open phil-s opened 3 weeks ago

phil-s commented 3 weeks ago

I wanted this just now, so I whipped up the following (which I based on the code for dape-info-variable-edit).

(dape--command-at-line dape-info-variable-value-copy
  (dape--info-ref dape--info-variable)
  "Copy variable value to the kill ring."
  (kill-new (or (plist-get dape--info-variable :value)
                (plist-get dape--info-variable :result)))
  (message "Copied value of %s" (plist-get dape--info-variable :name)))

(define-key dape-info-scope-mode-map "w" 'dape-info-variable-value-copy)

That seems to me like a useful thing.

This version does not handle compound data types, so you could use it to copy the string value of an array element, but not to copy the whole array. I assume this can be fixed, but I've not looked into it yet.


Edit: Looked into it, and... it's a bit awkward -- we have to invent our own syntax for formatting it. Here's a first pass at something more useful than the first version. It's non-recursive, so it's only a first step. Also, the debugger appears to not have access to the expanded value until you've expanded it in the scope window -- at which point it must send a request to the adapter for more information. So you need to do that before copying.

(dape--command-at-line dape-info-variable-value-copy
  (dape--info-ref dape--info-variable)
  "Copy variable value to the kill ring."
  (kill-new (or (when-let ((vars (plist-get dape--info-variable :variables)))
                  (concat (plist-get dape--info-variable :value)
                          "\n("
                          (mapconcat (lambda (v)
                                       (format "(%s . %s)"
                                               (plist-get v :name)
                                               (plist-get v :value)))
                                     vars "\n")
                          ")"))
                (plist-get dape--info-variable :value)
                (plist-get dape--info-variable :result)))
  (message "Copied value of %s" (plist-get dape--info-variable :name)))
phil-s commented 3 weeks ago

Edit: This comment/problem is now resolved (the updated comment text has the details). However:

It might be worth adding some defaults to the standard config, if just for user-visibility of how to configure this.


Oh, damn... I've just seen that a string value I was copying has been truncated at exactly 1024 chars, so I can't see the whole value.

That's not good. Is that a normal DAP thing? Can I configure it?

(get-text-property (point) 'dape--info-variable) doesn't show me any alternative plist entries with the full value.

I see that dape-memory-page-size is 1024, but I can't guess whether that's relevant, nor what the effects of changing it mid-session might be. I don't think it's relevant, though.

When I evaluate (dape--current-stack-frame (dape--live-connection 'stopped t)) I can again only see the truncated value. It's starting to feel like this is all that was ever supplied to dape...

...and I think this turns out to be something configurable for the adapter I'm using via launch.json, so I need to figure out the dape-equivalent for that config...

...sweet, got that sorted.

FYI, this issue was with xdebug for PHP, which has configurable limits for how much data to show, and I found in the adapter's documentation:

- `xdebugSettings`: Allows you to override Xdebug's remote debugging settings to fine tuning Xdebug to your needs. For example, you can play with `max_children` and `max_depth` to change the max number of array and object children that are retrieved and the max depth in structures like arrays and objects. This can speed up the debugger on slow machines.
  For a full list of feature names that can be set please refer to the [Xdebug documentation](https://xdebug.org/docs-dbgp.php#feature-names).
  - `max_children`: max number of array or object children to initially retrieve
  - `max_data`: max amount of variable data to initially retrieve.
  - `max_depth`: maximum depth that the debugger engine may return when sending arrays, hashes or object structures to the IDE (there should be no need to change this as depth is retrieved incrementally, large value can cause IDE to hang).
  - `show_hidden`: This feature can get set by the IDE if it wants to have more detailed internal information on properties (eg. private members of classes, etc.) Zero means that hidden members are not shown to the IDE.

So I added this to the xdebug section of dape-configs:

     :xdebugSettings ( :max_children 1024
                       :max_data 16384
                       :max_depth 64)

I'd also expected I could fix this in the xdebug extension config file using https://xdebug.org/docs/all_settings#var_display_max_children but it's not the case -- I can make settings there, and I can verify them in dape's REPL with ini_get('xdebug.var_display_max_data'); (for example), but I still see the 1024 char limit. AFAICS this does need to be set explicitly for the debugger in order for the data to flow through to dape.

(That also explains why I'd been seeing an effective limit of 1024 while the xdebug defaults seemed to be only 512.)

I can set this in my config with:

(let ((xdebug-config (alist-get 'xdebug dape-configs)))
  (plist-put xdebug-config :xdebugSettings
             '( :max_children 1024
                :max_data 16384
                :max_depth 64 )))

It might be worth adding some defaults to the standard config, if just for user-visibility of how to configure this.

phil-s commented 2 weeks ago

we have to invent our own syntax for formatting it

I guess the adapter needs to support the supportsValueFormattingOptions capability in order for a language-specific formatter to be available for complex values.

(In the absence of that capability, I think it would be reasonable to use something lisp-y.)

Based on https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Variables

interface VariablesArguments {
  [...]
  /**
   * Specifies details on how to format the Variable values.
   * The attribute is only honored by a debug adapter if the corresponding
   * capability `supportsValueFormattingOptions` is true.
   */
  format?: ValueFormat;
}

(Which I might be misinterpreting.)

svaante commented 4 days ago

Sorry for taking such a long time responding.

It might be worth adding some defaults to the standard config, if just for user-visibility of how to configure this. I agree, would you mind opening up an PR with good default values for :xdebugSettings? If you choose not to let me know and I can add them myself.

Would something like an command for expanding an variable fully then copy pasting from scope buffer be sufficient? Or do you expect something which concatenates the results of an recursive expansion of the variable?

supportsValueFormattingOptions specification is lacking and I have yet to find out how format is supposed to be used.