Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple assemblies decompilation into a Visual Studio Solution #1550

Merged
merged 10 commits into from
Jul 26, 2019
Merged

Conversation

dymanoid
Copy link
Contributor

My proposal of #972 implementation.

@dymanoid dymanoid changed the title Multiple projects decompilation into a Visual Studio Solution Multiple assemblies decompilation into a Visual Studio Solution Jun 21, 2019
@siegfriedpammer siegfriedpammer self-assigned this Jul 23, 2019
@siegfriedpammer
Copy link
Member

Thank you for adding this feature!

I refactored your code a bit to make it work with Language directly instead of ILSpyTreeNode.

void SaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
var focusedElement = FocusManager.GetFocusedElement(this) as DependencyObject;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why this is needed at all. The only case I could think of would be that the list of assemblies is empty and one still would want to save the current output.

Could you explain the reason for the focus check? Thank you!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thoughts were as following.
The 'Save' command should be allowed for the following cases:

  • the user wants to save the content of the code view
  • the user wants to save the selected node from the tree view (single node selected, e.g. class or assembly)
  • the user wants to save a Visual Studio solution (multiple assembly nodes selected)

So the command enabling seems to depend on what the user does. If they select nodes in the tree list, they want to do 2 or 3. If they select text in the code view or navigate there or whatever, they most probably want to save the code view content.

However, when multiple nodes are selected in the tree view, the 'Save' command should be disabled (unless all these nodes are assemblies). This is to prevent an unclear intent (don't want to/cannot save partial assemblies or namespaces or types).

So in the latter case (multiple non-assembly nodes selected) we still want to allow user to save the code view content, if they navigate/work with it, even while the "invalid" nodes are selected in the tree view.

Maybe I'm over-engineering this, but it seemed logical to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand, but I am not quite sure about this.

Currently the content of the DecompilerTextView is transient (vanishes as soon as the tree view selection changes) and cannot be persisted independently from the tree view. When you select "Save Code" from the file menu, we always trigger a new decompilation task that directly writes the selected tree nodes to one or multiple files.

This has two advantages:

  • If the user selects too much code (a very large amount of tree nodes that would cause the text editor or ILSpy to become unresponsive), we can cancel the text view output and allow the user to directly save the code to files.
  • When decompiling code for display in the decompiler text view, we do not escape invalid characters (e.g. identifiers of compiler-generated types and members), because we want to show the code as is to the user. If the user selects "Save Code", we escape all invalid identifiers, so the decompiled code is suitable for consumption by a compiler or other tools.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, when multiple nodes are selected in the tree view, the 'Save' command should be disabled (unless all these nodes are assemblies). This is to prevent an unclear intent (don't want to/cannot save partial assemblies or namespaces or types).

I just tested this without your modifications, yes, it definitely leads to strange behavior when selecting multiple tree nodes that are not assemblies. This is a good change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After experimenting with this a bit more: I think it is a good idea to make the "Save Code" feature more restrictive. I think the following rules would be good:

  • Single selection:

    • If it's an assembly: Provide three options: Save code, Save code (full), decompile as csproj
    • else: Save code
  • Multiple selection:

    • If not all selected items are of the same type: disable "Save Code"
    • If all selected items are assemblies: Do solution decompilation
    • Otherwise: Decompile all items into a single file.

I will add an implementation to this pull request, so we can play around with it, if needed :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addendum:

In the case of multi-selection with only assemblies: should we provide the other decompilation types ("Save Code" and "Save Code (full)") as well?

Currently these are two different code paths, which I do not really like.

Copy link
Contributor Author

@dymanoid dymanoid Jul 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've always found the 'Save' functionality in ILSpy a little bit confusing. You never know what you get.
I think a neat and clean solution would be to explicitly separate the 'save code' aspects so that the user decides what they want to save.
Like, there are multiple menu items which are enabled/disabled (or shown/hidden) according to the current context:

  • save the contents of the code view
  • save the code of the selected nodes
  • save a csproj
  • save a solution

So the user won't guess what will happen on selecting 'Save', but rather will actively tell what they want to do.

What do you think about it?

(Could be a little bit off-topic for this PR though.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've always found the 'Save' functionality in ILSpy a little bit confusing. You never know what you get.

The workflow as it was intended:

  1. Select the target language from the dropdown
  2. Select the parts of the assembly you want to decompile
  3. Click "Save Code"
  4. In the Save dialog: Select the format you want from the "file types" dropdown.
  5. Save.

Depending on the context the file types could be:

  • Single file
  • Single file (full) (only available, iff one assembly node is selected)
  • Project (only available, iff one assembly node is selected)
  • Solution (only available iff all selected nodes are assembly nodes)

So "what you get" is what you select from the "file types" dropdown...

…ot necessary.

Remove focused element check in SaveCommandCanExecute, because saving the text view content independently from the tree view selection is currently not supported.
@siegfriedpammer siegfriedpammer merged commit 1a2929c into icsharpcode:master Jul 26, 2019
@siegfriedpammer
Copy link
Member

Thank you very much for providing this feature!

@ciwei100000
Copy link

This feature is awesome! :D

@marwie
Copy link
Contributor

marwie commented Apr 3, 2021

Is this feature available to the commandline as well? @siegfriedpammer @dymanoid

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants