Skip to content

Commit 7bad057

Browse files
author
Evgen Vidolob
authored
eclipse-che#3220 use document changes instead of full text replacing on organize import operation (eclipse-che#3409)
Signed-off-by: Evgen Vidolob <evidolob@codenvy.com>
1 parent 67e303e commit 7bad057

7 files changed

Lines changed: 115 additions & 58 deletions

File tree

plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/editor/JavaCodeAssistClient.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.eclipse.che.ide.api.machine.WsAgentURLModifier;
2424
import org.eclipse.che.ide.ext.java.shared.dto.Change;
2525
import org.eclipse.che.ide.ext.java.shared.dto.ConflictImportDTO;
26+
import org.eclipse.che.ide.ext.java.shared.dto.OrganizeImportResult;
2627
import org.eclipse.che.ide.ext.java.shared.dto.Problem;
2728
import org.eclipse.che.ide.ext.java.shared.dto.ProposalApplyResult;
2829
import org.eclipse.che.ide.ext.java.shared.dto.Proposals;
@@ -151,13 +152,13 @@ public List<Change> apply(List<Change> arg) throws FunctionException {
151152
* fully qualified name of the java file
152153
* @return list of imports which have conflicts
153154
*/
154-
public Promise<List<ConflictImportDTO>> organizeImports(String projectPath, String fqn) {
155+
public Promise<OrganizeImportResult> organizeImports(String projectPath, String fqn) {
155156
String url =
156157
appContext.getDevMachine().getWsAgentBaseUrl() + CODE_ASSIST_URL_PREFIX + "/organize-imports?projectpath=" + projectPath +
157158
"&fqn=" + fqn;
158159
return asyncRequestFactory.createPostRequest(url, null)
159160
.loader(loader)
160-
.send(unmarshallerFactory.newListUnmarshaller(ConflictImportDTO.class));
161+
.send(unmarshallerFactory.newUnmarshaller(OrganizeImportResult.class));
161162
}
162163

163164
/**
@@ -168,12 +169,12 @@ public Promise<List<ConflictImportDTO>> organizeImports(String projectPath, Stri
168169
* @param fqn
169170
* fully qualified name of the java file
170171
*/
171-
public Promise<Void> applyChosenImports(String projectPath, String fqn, ConflictImportDTO chosen) {
172+
public Promise<List<Change>> applyChosenImports(String projectPath, String fqn, ConflictImportDTO chosen) {
172173
String url = appContext.getDevMachine().getWsAgentBaseUrl() + CODE_ASSIST_URL_PREFIX + "/apply-imports?projectpath=" + projectPath +
173174
"&fqn=" + fqn;
174175
return asyncRequestFactory.createPostRequest(url, chosen)
175176
.loader(loader)
176177
.header(CONTENT_TYPE, MimeType.APPLICATION_JSON)
177-
.send();
178+
.send(unmarshallerFactory.newListUnmarshaller(Change.class));
178179
}
179180
}

plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/organizeimports/OrganizeImportsPresenter.java

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
import org.eclipse.che.ide.ext.java.client.editor.JavaCodeAssistClient;
3535
import org.eclipse.che.ide.ext.java.client.resource.SourceFolderMarker;
3636
import org.eclipse.che.ide.ext.java.client.util.JavaUtil;
37+
import org.eclipse.che.ide.ext.java.shared.dto.Change;
3738
import org.eclipse.che.ide.ext.java.shared.dto.ConflictImportDTO;
39+
import org.eclipse.che.ide.ext.java.shared.dto.OrganizeImportResult;
3840
import org.eclipse.che.ide.util.loging.Log;
3941

4042
import java.util.ArrayList;
@@ -110,13 +112,13 @@ public void organizeImports(EditorPartPresenter editor) {
110112

111113
eventBus.fireEvent(newFileTrackingSuspendEvent());
112114
javaCodeAssistClient.organizeImports(project.get().getLocation().toString(), fqn)
113-
.then(new Operation<List<ConflictImportDTO>>() {
115+
.then(new Operation<OrganizeImportResult>() {
114116
@Override
115-
public void apply(List<ConflictImportDTO> choices) throws OperationException {
116-
if (!choices.isEmpty()) {
117-
show(choices);
117+
public void apply(OrganizeImportResult result) throws OperationException {
118+
if (result.getConflicts() != null && !result.getConflicts().isEmpty()) {
119+
show(result.getConflicts());
118120
} else {
119-
applyChanges(file);
121+
applyChanges(document, result.getChanges());
120122
}
121123
eventBus.fireEvent(newFileTrackingResumeEvent());
122124
}
@@ -166,10 +168,10 @@ public void onFinishButtonClicked() {
166168
final Optional<Project> project = ((Resource)file).getRelatedProject();
167169

168170
javaCodeAssistClient.applyChosenImports(project.get().getLocation().toString(), JavaUtil.resolveFQN(file), result)
169-
.then(new Operation<Void>() {
171+
.then(new Operation<List<Change>>() {
170172
@Override
171-
public void apply(Void arg) throws OperationException {
172-
applyChanges(file);
173+
public void apply(List<Change> result) throws OperationException {
174+
applyChanges(((TextEditor) editor).getDocument(), result);
173175
view.hide();
174176
((TextEditor)editor).setFocus();
175177
}
@@ -214,10 +216,12 @@ private void show(List<ConflictImportDTO> choices) {
214216
/**
215217
* Update content of the file.
216218
*
217-
* @param file
218-
* current file
219+
* @param document
220+
* current document
221+
* @param changes
222+
*
219223
*/
220-
private void applyChanges(VirtualFile file) {
224+
private void applyChanges(Document document, List<Change> changes) {
221225
HandlesUndoRedo undoRedo = null;
222226
if (editor instanceof UndoableEditor) {
223227
undoRedo = ((UndoableEditor)editor).getUndoRedo();
@@ -226,7 +230,9 @@ private void applyChanges(VirtualFile file) {
226230
if (undoRedo != null) {
227231
undoRedo.beginCompoundChange();
228232
}
229-
replaceContent(file, document);
233+
for (Change change : changes) {
234+
document.replace(change.getOffset(), change.getLength(), change.getText());
235+
}
230236
} catch (final Exception e) {
231237
Log.error(getClass(), e);
232238
} finally {
@@ -236,17 +242,6 @@ private void applyChanges(VirtualFile file) {
236242
}
237243
}
238244

239-
private void replaceContent(VirtualFile file, final Document document) {
240-
if (file instanceof File) {
241-
file.getContent().then(new Operation<String>() {
242-
@Override
243-
public void apply(String content) throws OperationException {
244-
document.replace(0, document.getContents().length(), content);
245-
}
246-
});
247-
}
248-
}
249-
250245
private void updateButtonsState() {
251246
view.setEnableBackButton(!isFirstPage());
252247
view.setEnableNextButton(!isLastPage());

plugins/plugin-java/che-plugin-java-ext-lang-client/src/test/java/org/eclipse/che/ide/ext/java/client/organizeimports/OrganizeImportsPresenterTest.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import org.eclipse.che.ide.ext.java.client.JavaLocalizationConstant;
2929
import org.eclipse.che.ide.ext.java.client.editor.JavaCodeAssistClient;
3030
import org.eclipse.che.ide.ext.java.client.resource.SourceFolderMarker;
31+
import org.eclipse.che.ide.ext.java.shared.dto.Change;
3132
import org.eclipse.che.ide.ext.java.shared.dto.ConflictImportDTO;
33+
import org.eclipse.che.ide.ext.java.shared.dto.OrganizeImportResult;
3234
import org.eclipse.che.ide.resource.Path;
3335
import org.junit.Before;
3436
import org.junit.Test;
@@ -84,16 +86,20 @@ public class OrganizeImportsPresenterTest {
8486
@Mock
8587
private Document document;
8688
@Mock
87-
private Promise<List<ConflictImportDTO>> importsPromise;
89+
private Promise<OrganizeImportResult> importsPromise;
8890
@Mock
89-
private Promise<Void> resolveConflictsPromise;
91+
private Promise<List<Change>> resolveConflictsPromise;
9092
@Mock
9193
private Promise<String> contentPromise;
94+
@Mock
95+
private OrganizeImportResult organizeImportResult;
96+
@Mock
97+
private Change change;
9298

9399
@Captor
94-
private ArgumentCaptor<Operation<List<ConflictImportDTO>>> importsOperation;
100+
private ArgumentCaptor<Operation<OrganizeImportResult>> importsOperation;
95101
@Captor
96-
private ArgumentCaptor<Operation<Void>> resolveConflictsOperation;
102+
private ArgumentCaptor<Operation<List<Change>>> resolveConflictsOperation;
97103
@Captor
98104
private ArgumentCaptor<Operation<String>> contentCaptor;
99105

@@ -117,7 +123,7 @@ public void setUp() throws Exception {
117123
when(relatedProject.getLocation()).thenReturn(Path.valueOf("/project"));
118124

119125
when(javaCodeAssistClient.organizeImports(anyString(), anyString())).thenReturn(importsPromise);
120-
when(importsPromise.then(Matchers.<Operation<List<ConflictImportDTO>>>anyObject())).thenReturn(importsPromise);
126+
when(importsPromise.then(Matchers.<Operation<OrganizeImportResult>>anyObject())).thenReturn(importsPromise);
121127

122128
presenter = new OrganizeImportsPresenter(view,
123129
javaCodeAssistClient,
@@ -134,15 +140,16 @@ public void setUp() throws Exception {
134140
public void organizeImportsShouldBeDoneWithoutConflicts() throws Exception {
135141
when(file.getContent()).thenReturn(contentPromise);
136142
when(contentPromise.then(any(Operation.class))).thenReturn(contentPromise);
137-
143+
when(organizeImportResult.getConflicts()).thenReturn(null);
144+
when(organizeImportResult.getChanges()).thenReturn(Collections.singletonList(change));
145+
when(change.getOffset()).thenReturn(0);
146+
when(change.getLength()).thenReturn("content".length());
147+
when(change.getText()).thenReturn("content");
138148
presenter.organizeImports(editor);
139149

140150
verify(javaCodeAssistClient).organizeImports(eq("/project"), eq("a.b.A"));
141151
verify(importsPromise).then(importsOperation.capture());
142-
importsOperation.getValue().apply(Collections.emptyList());
143-
144-
verify(file.getContent()).then(contentCaptor.capture());
145-
contentCaptor.getValue().apply("content");
152+
importsOperation.getValue().apply(organizeImportResult);
146153

147154
verify(document).replace(eq(0), eq("content".length()), eq("content"));
148155
}
@@ -176,10 +183,11 @@ private void showOrganizeImportsWindow() throws Exception {
176183
presenter.organizeImports(editor);
177184

178185
List<ConflictImportDTO> result = Arrays.asList(conflict1, conflict2);
186+
when(organizeImportResult.getConflicts()).thenReturn(result);
179187

180188
verify(javaCodeAssistClient).organizeImports(eq("/project"), eq("a.b.A"));
181189
verify(importsPromise).then(importsOperation.capture());
182-
importsOperation.getValue().apply(result);
190+
importsOperation.getValue().apply(organizeImportResult);
183191
}
184192

185193
@Test
@@ -230,7 +238,7 @@ public void focusShouldBeSetAfterApplyingConflicts() throws Exception {
230238
when(dtoFactory.createDto(ConflictImportDTO.class)).thenReturn(conflict1);
231239
when(conflict1.withTypeMatches(Matchers.<List<String>>anyObject())).thenReturn(conflict1);
232240
when(javaCodeAssistClient.applyChosenImports(anyString(), anyString(), any())).thenReturn(resolveConflictsPromise);
233-
when(resolveConflictsPromise.then(Matchers.<Operation<Void>>anyObject())).thenReturn(resolveConflictsPromise);
241+
when(resolveConflictsPromise.then(Matchers.<Operation<List<Change>>>anyObject())).thenReturn(resolveConflictsPromise);
234242

235243
showOrganizeImportsWindow();
236244
presenter.onFinishButtonClicked();

plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/CodeAssist.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.che.dto.server.DtoFactory;
2121
import org.eclipse.che.ide.ext.java.shared.dto.Change;
2222
import org.eclipse.che.ide.ext.java.shared.dto.ConflictImportDTO;
23+
import org.eclipse.che.ide.ext.java.shared.dto.OrganizeImportResult;
2324
import org.eclipse.che.ide.ext.java.shared.dto.Problem;
2425
import org.eclipse.che.ide.ext.java.shared.dto.ProposalApplyResult;
2526
import org.eclipse.che.ide.ext.java.shared.dto.ProposalPresentation;
@@ -55,6 +56,7 @@
5556
import org.eclipse.jdt.internal.core.JavaModelStatus;
5657
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
5758
import org.eclipse.jdt.internal.corext.codemanipulation.OrganizeImportsOperation;
59+
import org.eclipse.jdt.internal.corext.format.DocumentChangeListener;
5860
import org.eclipse.jdt.internal.corext.refactoring.changes.MoveCompilationUnitChange;
5961
import org.eclipse.jdt.internal.corext.refactoring.changes.RenameCompilationUnitChange;
6062
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
@@ -66,6 +68,7 @@
6668
import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
6769
import org.eclipse.jdt.ui.text.java.correction.ChangeCorrectionProposal;
6870
import org.eclipse.jface.text.BadLocationException;
71+
import org.eclipse.jface.text.Document;
6972
import org.eclipse.jface.text.DocumentEvent;
7073
import org.eclipse.jface.text.IDocument;
7174
import org.eclipse.jface.text.IDocumentListener;
@@ -233,7 +236,7 @@ public String getJavaDoc(String sessionId, int index) {
233236
* fully qualified name of the java file
234237
* @return list of imports which have conflicts
235238
*/
236-
public List<ConflictImportDTO> organizeImports(IJavaProject project, String fqn) throws CoreException, BadLocationException {
239+
public OrganizeImportResult organizeImports(IJavaProject project, String fqn) throws CoreException, BadLocationException {
237240
ICompilationUnit compilationUnit = prepareCompilationUnit(project, fqn);
238241
return createOrganizeImportOperation(compilationUnit, null);
239242
}
@@ -248,13 +251,14 @@ public List<ConflictImportDTO> organizeImports(IJavaProject project, String fqn)
248251
* @param chosen
249252
* list of chosen imports as result of resolving conflicts which needed to add to all imports.
250253
*/
251-
public void applyChosenImports(IJavaProject project, String fqn, List<String> chosen) throws CoreException, BadLocationException {
254+
public List<Change> applyChosenImports(IJavaProject project, String fqn, List<String> chosen) throws CoreException, BadLocationException {
252255
ICompilationUnit compilationUnit = prepareCompilationUnit(project, fqn);
253-
createOrganizeImportOperation(compilationUnit, chosen);
256+
OrganizeImportResult result = createOrganizeImportOperation(compilationUnit, chosen);
257+
return result.getChanges();
254258
}
255259

256-
private List<ConflictImportDTO> createOrganizeImportOperation(ICompilationUnit compilationUnit,
257-
List<String> chosen) throws CoreException {
260+
private OrganizeImportResult createOrganizeImportOperation(ICompilationUnit compilationUnit,
261+
List<String> chosen) throws CoreException {
258262
CodeGenerationSettings settings = JavaPreferencesSettings.getCodeGenerationSettings(compilationUnit.getJavaProject());
259263

260264
OrganizeImportsOperation operation = new OrganizeImportsOperation(compilationUnit,
@@ -267,16 +271,25 @@ private List<ConflictImportDTO> createOrganizeImportOperation(ICompilationUnit c
267271

268272
NullProgressMonitor monitor = new NullProgressMonitor();
269273
TextEdit edit = operation.createTextEdit(monitor);
270-
274+
OrganizeImportResult result = DtoFactory.newDto(OrganizeImportResult.class);
271275
TypeNameMatch[][] choices = operation.getChoices();
272276
//Apply organize import declarations if operation doesn't have conflicts (choices.length == 0)
273277
//or all conflicts were resolved (!chosen.isEmpty())
274278
if ((chosen != null && !chosen.isEmpty()) || choices == null || choices.length == 0) {
275-
operation.applyChanges(edit, monitor);
276-
return Collections.emptyList();
279+
IBuffer buffer = compilationUnit.getBuffer();
280+
IDocument document = new Document(buffer.getContents());
281+
DocumentChangeListener documentChangeListener = new DocumentChangeListener(document);
282+
try {
283+
edit.apply(document);
284+
} catch (BadLocationException e) {
285+
LOG.debug("Applying Organize import text edits goes wrong:", e);
286+
}
287+
result.setChanges(documentChangeListener.getChanges());
288+
return result;
277289
}
278290

279-
return createListOfDTOMatches(choices);
291+
result.setConflicts(createListOfDTOMatches(choices));
292+
return result;
280293
}
281294

282295
private List<ConflictImportDTO> createListOfDTOMatches(TypeNameMatch[][] choices) {

plugins/plugin-java/che-plugin-java-ext-lang-server/src/main/java/org/eclipse/che/plugin/java/server/rest/CodeAssistService.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@
1313

1414
import io.swagger.annotations.ApiOperation;
1515
import io.swagger.annotations.ApiParam;
16-
import io.swagger.annotations.ApiResponse;
17-
import io.swagger.annotations.ApiResponses;
1816

1917
import org.eclipse.che.api.core.NotFoundException;
2018
import org.eclipse.che.ide.ext.java.shared.dto.Change;
2119
import org.eclipse.che.ide.ext.java.shared.dto.ConflictImportDTO;
20+
import org.eclipse.che.ide.ext.java.shared.dto.OrganizeImportResult;
2221
import org.eclipse.che.ide.ext.java.shared.dto.Problem;
2322
import org.eclipse.che.ide.ext.java.shared.dto.ProposalApplyResult;
2423
import org.eclipse.che.ide.ext.java.shared.dto.Proposals;
@@ -112,8 +111,8 @@ public String getJavaDoc(@QueryParam("sessionid") String sessionId,
112111
@POST
113112
@Path("/organize-imports")
114113
@Produces({MediaType.APPLICATION_JSON})
115-
public List<ConflictImportDTO> organizeImports(@QueryParam("projectpath") String projectPath,
116-
@QueryParam("fqn") String fqn) throws NotFoundException,
114+
public OrganizeImportResult organizeImports(@QueryParam("projectpath") String projectPath,
115+
@QueryParam("fqn") String fqn) throws NotFoundException,
117116
CoreException,
118117
BadLocationException {
119118
IJavaProject project = model.getJavaProject(projectPath);
@@ -128,18 +127,19 @@ public List<ConflictImportDTO> organizeImports(@QueryParam("projectpath") String
128127
* @param fqn
129128
* fully qualified name of the java file
130129
* @param chosen
131-
* list of chosen imports from conflicts which needed to add to all imports.
130+
* @return list of document changes
132131
*/
133132
@POST
134133
@Path("/apply-imports")
135134
@Consumes(MediaType.APPLICATION_JSON)
136-
public void applyChosenImports(@QueryParam("projectpath") String projectPath,
137-
@QueryParam("fqn") String fqn,
138-
ConflictImportDTO chosen) throws NotFoundException,
135+
@Produces(MediaType.APPLICATION_JSON)
136+
public List<Change> applyChosenImports(@QueryParam("projectpath") String projectPath,
137+
@QueryParam("fqn") String fqn,
138+
ConflictImportDTO chosen) throws NotFoundException,
139139
CoreException,
140140
BadLocationException {
141141
IJavaProject project = model.getJavaProject(projectPath);
142-
codeAssist.applyChosenImports(project, fqn, chosen.getTypeMatches());
142+
return codeAssist.applyChosenImports(project, fqn, chosen.getTypeMatches());
143143
}
144144

145145
@POST

0 commit comments

Comments
 (0)