Skip to content

Commit ae03105

Browse files
Merge pull request #1606 from DustinCampbell/fix-refactorings
Use correct span when requesting code actions from OmniSharp
2 parents e09c9ea + abbdaf7 commit ae03105

File tree

2 files changed

+70
-36
lines changed

2 files changed

+70
-36
lines changed

src/features/codeActionProvider.ts

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
'use strict';
77

8-
import {CodeActionProvider, CodeActionContext, Command, CancellationToken, TextDocument, WorkspaceEdit, TextEdit, Range, Uri, workspace, commands} from 'vscode';
9-
import {OmniSharpServer} from '../omnisharp/server';
8+
import * as vscode from 'vscode';
9+
import { OmniSharpServer } from '../omnisharp/server';
1010
import AbstractProvider from './abstractProvider';
1111
import * as protocol from '../omnisharp/protocol';
12-
import {toRange2} from '../omnisharp/typeConvertion';
12+
import { toRange2 } from '../omnisharp/typeConvertion';
1313
import * as serverUtils from '../omnisharp/utils';
1414

15-
export default class OmnisharpCodeActionProvider extends AbstractProvider implements CodeActionProvider {
15+
export default class CodeActionProvider extends AbstractProvider implements vscode.CodeActionProvider {
1616

1717
private _disabled: boolean;
1818
private _commandId: string;
@@ -21,38 +21,80 @@ export default class OmnisharpCodeActionProvider extends AbstractProvider implem
2121
super(server);
2222
this._commandId = 'omnisharp.runCodeAction';
2323

24-
this._updateEnablement();
25-
let d1 = workspace.onDidChangeConfiguration(this._updateEnablement, this);
26-
let d2 = commands.registerCommand(this._commandId, this._runCodeAction, this);
24+
this._checkOption();
25+
26+
let d1 = vscode.workspace.onDidChangeConfiguration(this._checkOption, this);
27+
let d2 = vscode.commands.registerCommand(this._commandId, this._runCodeAction, this);
2728
this._disposables.push(d1, d2);
2829
}
2930

30-
private _updateEnablement(): void {
31-
let value = workspace.getConfiguration().get('csharp.disableCodeActions', false);
31+
private _checkOption(): void {
32+
let value = vscode.workspace.getConfiguration().get('csharp.disableCodeActions', false);
3233
this._disabled = value;
3334
}
3435

35-
public provideCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): Promise<Command[]> {
36+
public provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise<vscode.Command[]> {
3637
if (this._disabled) {
3738
return;
3839
}
3940

40-
let req: protocol.V2.GetCodeActionsRequest = {
41+
let line: number;
42+
let column: number;
43+
let selection: protocol.V2.Range;
44+
45+
// VS Code will pass the range of the word at the editor caret, even if there isn't a selection.
46+
// To ensure that we don't suggest selection-based refactorings when there isn't a selection, we first
47+
// find the text editor for this document and verify that there is a selection.
48+
let editor = vscode.window.visibleTextEditors.find(e => e.document === document);
49+
if (editor) {
50+
if (editor.selection.isEmpty) {
51+
// The editor does not have a selection. Use the active position of the selection (i.e. the caret).
52+
let active = editor.selection.active;
53+
54+
line = active.line + 1;
55+
column = active.character + 1;
56+
}
57+
else {
58+
// The editor has a selection. Use it.
59+
let start = editor.selection.start;
60+
let end = editor.selection.end;
61+
62+
selection = {
63+
Start: { Line: start.line + 1, Column: start.character + 1 },
64+
End: { Line: end.line + 1, Column: end.character + 1 }
65+
};
66+
}
67+
}
68+
else {
69+
// We couldn't find the editor, so just use the range we were provided.
70+
selection = {
71+
Start: { Line: range.start.line + 1, Column: range.start.character + 1 },
72+
End: { Line: range.end.line + 1, Column: range.end.character + 1 }
73+
};
74+
}
75+
76+
let request: protocol.V2.GetCodeActionsRequest = {
4177
FileName: document.fileName,
42-
Selection: OmnisharpCodeActionProvider._asRange(range)
78+
Line: line,
79+
Column: column,
80+
Selection: selection
4381
};
4482

45-
return serverUtils.getCodeActions(this._server, req, token).then(response => {
83+
return serverUtils.getCodeActions(this._server, request, token).then(response => {
4684
return response.CodeActions.map(codeAction => {
85+
let runRequest: protocol.V2.RunCodeActionRequest = {
86+
FileName: document.fileName,
87+
Line: line,
88+
Column: column,
89+
Selection: selection,
90+
Identifier: codeAction.Identifier,
91+
WantsTextChanges: true
92+
};
93+
4794
return {
4895
title: codeAction.Name,
4996
command: this._commandId,
50-
arguments: [<protocol.V2.RunCodeActionRequest>{
51-
FileName: document.fileName,
52-
Selection: OmnisharpCodeActionProvider._asRange(range),
53-
Identifier: codeAction.Identifier,
54-
WantsTextChanges: true
55-
}]
97+
arguments: [runRequest]
5698
};
5799
});
58100
}, (error) => {
@@ -66,31 +108,23 @@ export default class OmnisharpCodeActionProvider extends AbstractProvider implem
66108

67109
if (response && Array.isArray(response.Changes)) {
68110

69-
let edit = new WorkspaceEdit();
111+
let edit = new vscode.WorkspaceEdit();
70112

71113
for (let change of response.Changes) {
72-
let uri = Uri.file(change.FileName);
73-
let edits: TextEdit[] = [];
114+
let uri = vscode.Uri.file(change.FileName);
115+
let edits: vscode.TextEdit[] = [];
74116
for (let textChange of change.Changes) {
75-
edits.push(TextEdit.replace(toRange2(textChange), textChange.NewText));
117+
edits.push(vscode.TextEdit.replace(toRange2(textChange), textChange.NewText));
76118
}
77119

78120
edit.set(uri, edits);
79121
}
80122

81-
return workspace.applyEdit(edit);
123+
return vscode.workspace.applyEdit(edit);
82124
}
83125

84126
}, (error) => {
85-
return Promise.reject('Problem invoking \'RunCodeAction\' on OmniSharp server: ' + error);
127+
return Promise.reject(`Problem invoking 'RunCodeAction' on OmniSharp server: ${error}`);
86128
});
87129
}
88-
89-
private static _asRange(range: Range): protocol.V2.Range {
90-
let {start, end} = range;
91-
return {
92-
Start: { Line: start.line + 1, Column: start.character + 1 },
93-
End: { Line: end.line + 1, Column: end.character + 1 }
94-
};
95-
}
96-
}
130+
}

src/omnisharp/protocol.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ export namespace V2 {
436436
}
437437

438438
export interface GetCodeActionsRequest extends Request {
439-
Selection: Range;
439+
Selection?: Range;
440440
}
441441

442442
export interface OmniSharpCodeAction {
@@ -450,7 +450,7 @@ export namespace V2 {
450450

451451
export interface RunCodeActionRequest extends Request {
452452
Identifier: string;
453-
Selection: Range;
453+
Selection?: Range;
454454
WantsTextChanges: boolean;
455455
}
456456

0 commit comments

Comments
 (0)