Skip to content

feat: add outline drag-and-drop method extraction prototype#319320

Open
robot-mazeee wants to merge 2 commits into
microsoft:mainfrom
robot-mazeee:outline-drag-and-drop
Open

feat: add outline drag-and-drop method extraction prototype#319320
robot-mazeee wants to merge 2 commits into
microsoft:mainfrom
robot-mazeee:outline-drag-and-drop

Conversation

@robot-mazeee
Copy link
Copy Markdown

Add outline drag-and-drop method extraction prototype

Summary

Part of #299961.

This PR prototypes structural refactoring from the Outline view. It adds drag-and-drop handling for Outline symbols and routes supported moves to an experimental refactoring command.

The initial semantic implementation focuses on JavaScript class methods dragged outside their enclosing class. When the move can be statically validated, the method is transformed into a standalone function and direct call sites are updated.

Implementation approach

This prototype is implemented as a small experimental extension under extensions/outline-refactor, with a focused change in the built-in Outline view to dispatch supported drag-and-drop operations to the extension command.

The Outline view is responsible only for the interaction layer: detecting supported symbol drops, preserving existing Outline behavior for unsupported cases, and invoking the outline.moveSymbol command with the source symbol, target symbol, parent symbols, document URI, and drop position.

The extension contains the refactoring layer. It registers the outline.moveSymbol command, validates whether the requested move is safe, and applies the resulting edit through a WorkspaceEdit. The current semantic implementation uses the TypeScript compiler API to analyze JavaScript class methods and rewrite supported method-extraction cases.

This keeps the prototype split between:

  • Outline UI behavior in VS Code core
  • Language-specific refactoring logic in the experimental extension

The extension structure is intentionally designed so additional language engines could be added later without putting all semantic transformation logic directly into the Outline view.

What works

  • Dragging supported method symbols from the Outline view
  • Dispatching Outline drops to a refactoring command
  • Converting simple JavaScript class methods into standalone functions
  • Rewriting direct call sites such as this.helper(x)
  • Rewriting this usages inside the moved method when needed
  • Rejecting unsupported or unsafe method moves conservatively
  • Mocha fixture tests for supported and unsupported semantic cases

Supported cases

  • JavaScript files
  • Class methods with simple identifier names
  • Methods moved outside their enclosing class
  • Direct call sites of the form this.methodName(...)
  • Methods that use this, rewritten through an explicit receiver parameter

Example:

class Calculator {
	compute(x) {
		return this.helper(x) + 1;
	}

	helper(x) {
		return this.factor * x;
	}
}

becomes:

class Calculator {
	compute(x) {
		return helper(this, x) + 1;
	}
}

function helper(obj, x) {
	return obj.factor * x;
}

Unsupported cases

The prototype intentionally rejects cases that are not safely handled yet:

  • Constructors
  • Getters and setters
  • Class fields
  • Static methods
  • Private fields and private methods
  • super usage
  • Dynamic access such as this[name]
  • Indirect method references such as const fn = this.helper
  • Moving methods into another class
  • Cross-file moves

Testing

Automated semantic fixture tests:

cd extensions/outline-refactor
npm test

Testing

Automated semantic fixture tests:

cd extensions/outline-refactor
npm test

Current result:

9 passing

Also checked:

git diff --check

The full repository compile was run with:

npm run compile

and completed successfully locally.

Notes

This is intended as a prototype of the interaction and semantic-refactoring flow. The implementation is intentionally conservative: if a move cannot be statically validated by the current analysis, it is rejected instead of applying a potentially unsafe edit.

Co-authored with @leonor-a-a-ist.

Part of microsoft#299961.

This prototypes structural refactoring from the Outline view. Supported
drops are routed to an experimental outline-refactor extension.

The implementation is split between a small Outline UI change and a
language-specific refactoring engine. The Outline view detects
supported drops and invokes outline.moveSymbol with symbol and drop
metadata.

The extension registers the command, validates the move, and applies a
WorkspaceEdit. The JavaScript engine uses the TypeScript compiler API
to analyze class methods, rewrite direct this.method(...) call sites,
and convert the moved method to a standalone function.

Supported today:
- JavaScript class methods with simple identifier names.
- Moves from a class to the surrounding source file.
- Direct call sites of the form this.methodName(...).
- this usages rewritten through an explicit receiver parameter.

Unsupported cases are rejected conservatively, including constructors,
getters, setters, class fields, static methods, private members, super,
dynamic this[...] access, indirect references, cross-file moves, and
moving methods into another class.

Testing:
- npm test in extensions/outline-refactor.
- 9 semantic fixture tests passing.
- git diff --check.
- npm run compile completed successfully locally.

Co-authored-by: Leonor Azevedo <leonor.a.e.azevedo@tecnico.ulisboa.pt>
Copilot AI review requested due to automatic review settings June 1, 2026 12:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds experimental drag-and-drop refactoring from the Outline view by wiring tree DnD to a new outline.moveSymbol command, backed by a new outline-refactor extension that can extract JavaScript class methods into standalone functions.

Changes:

  • Add custom Outline tree drag-and-drop handling, including custom drag preview + command invocation.
  • Introduce outline-refactor extension with move-symbol command + JS method extraction engine.
  • Add fixtures and a Mocha test suite validating supported/unsupported refactor cases.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/vs/workbench/contrib/outline/browser/outlinePane.ts Adds custom tree DnD logic and dispatches outline.moveSymbol on drop.
src/vs/workbench/contrib/outline/browser/outlinePane.css Styles the custom drag image preview used during Outline DnD.
extensions/outline-refactor/tsconfig.json Adds TypeScript build configuration for the new extension.
extensions/outline-refactor/test-fixtures/unsupported/super.input.js Adds unsupported refactor fixture case (uses super).
extensions/outline-refactor/test-fixtures/unsupported/static-method.input.js Adds unsupported refactor fixture case (static method).
extensions/outline-refactor/test-fixtures/unsupported/private-field.input.js Adds unsupported refactor fixture case (private field).
extensions/outline-refactor/test-fixtures/unsupported/indirect-call.input.js Adds unsupported refactor fixture case (indirect call).
extensions/outline-refactor/test-fixtures/unsupported/getter.input.js Adds unsupported refactor fixture case (getter).
extensions/outline-refactor/test-fixtures/unsupported/dynamic-this.input.js Adds unsupported refactor fixture case (dynamic this[...]).
extensions/outline-refactor/test-fixtures/supported/uses-this.input.js Adds supported refactor fixture case (uses this).
extensions/outline-refactor/test-fixtures/supported/uses-this.expected.js Adds expected output for uses-this supported fixture.
extensions/outline-refactor/test-fixtures/supported/simple-no-this.input.js Adds supported refactor fixture case (no this).
extensions/outline-refactor/test-fixtures/supported/simple-no-this.expected.js Adds expected output for simple-no-this supported fixture.
extensions/outline-refactor/test-fixtures/supported/multiple-args.input.js Adds supported refactor fixture case (multiple args).
extensions/outline-refactor/test-fixtures/supported/multiple-args.expected.js Adds expected output for multiple-args supported fixture.
extensions/outline-refactor/src/test/javascriptMethodExtractEngine.test.ts Adds Mocha tests for the JS method extraction engine using fixtures.
extensions/outline-refactor/src/refactor/types.ts Defines refactor request/engine types shared across the extension.
extensions/outline-refactor/src/refactor/textMoveEngine.ts Implements a generic text-based “move symbol” edit builder.
extensions/outline-refactor/src/refactor/javascriptMethodExtractEngine.ts Implements JS-specific analysis + extraction refactor and call-site rewriting.
extensions/outline-refactor/src/extension.ts Registers the move-symbol command on activation.
extensions/outline-refactor/src/commands/moveSymbolCommand.ts Implements outline.moveSymbol command and applies the resulting edit.
extensions/outline-refactor/package.nls.json Adds localized strings for the extension display metadata and command title.
extensions/outline-refactor/package.json Declares the new extension and contributes the outline.moveSymbol command.

Comment thread src/vs/workbench/contrib/outline/browser/outlinePane.ts
Comment thread extensions/outline-refactor/package.json
Comment thread src/vs/workbench/contrib/outline/browser/outlinePane.ts
Avoid receiver parameter name collisions when extracting methods by
choosing a non-conflicting receiver name and adding a fixture test for
the obj-parameter case.

Restore the patched module loader after semantic tests to avoid leaking
the vscode stub across test files.

Limit expensive outline drop-feedback traversal to after-drops on class
symbols, reducing unnecessary work during drag-over events.

Co-authored-by: Leonor Azevedo <leonor.a.e.azevedo@tecnico.ulisboa.pt>
@bhavyaus bhavyaus assigned aiday-mar and unassigned bhavyaus Jun 1, 2026
@aiday-mar aiday-mar assigned alexdima and unassigned aiday-mar Jun 2, 2026
@alexdima alexdima added this to the Backlog milestone Jun 5, 2026
@alexdima alexdima added the feature-request Request for new features or functionality label Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature-request Request for new features or functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants