Skip to content

Commit 284ea9a

Browse files
committed
feat: Show variable definition as documentation
Resolve documentation requests immediately
1 parent 7ef3fa3 commit 284ea9a

28 files changed

+824
-754
lines changed

server/src/main/java/org/eclipse/lsp/cobol/service/CobolLanguageServer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public CompletableFuture<InitializeResult> initialize(@NonNull InitializeParams
9393
ServerCapabilities capabilities = new ServerCapabilities();
9494

9595
capabilities.setTextDocumentSync(Full);
96-
capabilities.setCompletionProvider(new CompletionOptions(true, emptyList()));
96+
capabilities.setCompletionProvider(new CompletionOptions(false, emptyList()));
9797
capabilities.setDefinitionProvider(TRUE);
9898
capabilities.setReferencesProvider(TRUE);
9999
capabilities.setDocumentFormattingProvider(TRUE);

server/src/main/java/org/eclipse/lsp/cobol/service/CobolTextDocumentService.java

+27-35
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,22 @@
1414
*/
1515
package org.eclipse.lsp.cobol.service;
1616

17+
import com.google.common.annotations.VisibleForTesting;
18+
import com.google.common.collect.ImmutableMap;
19+
import com.google.gson.Gson;
20+
import com.google.gson.JsonObject;
21+
import com.google.inject.Inject;
22+
import com.google.inject.Singleton;
23+
import lombok.Builder;
24+
import lombok.NonNull;
25+
import lombok.extern.slf4j.Slf4j;
1726
import org.eclipse.lsp.cobol.core.annotation.CheckServerShutdownState;
1827
import org.eclipse.lsp.cobol.core.annotation.DisposableService;
1928
import org.eclipse.lsp.cobol.domain.databus.api.DataBusBroker;
2029
import org.eclipse.lsp.cobol.domain.event.api.EventObserver;
2130
import org.eclipse.lsp.cobol.domain.event.model.AnalysisFinishedEvent;
22-
import org.eclipse.lsp.cobol.domain.event.model.DataEventType;
2331
import org.eclipse.lsp.cobol.domain.event.model.AnalysisResultEvent;
32+
import org.eclipse.lsp.cobol.domain.event.model.DataEventType;
2433
import org.eclipse.lsp.cobol.domain.event.model.RunAnalysisEvent;
2534
import org.eclipse.lsp.cobol.service.delegates.actions.CodeActions;
2635
import org.eclipse.lsp.cobol.service.delegates.communications.Communications;
@@ -31,15 +40,6 @@
3140
import org.eclipse.lsp.cobol.service.delegates.validations.AnalysisResult;
3241
import org.eclipse.lsp.cobol.service.delegates.validations.LanguageEngineFacade;
3342
import org.eclipse.lsp.cobol.service.utils.CustomThreadPoolExecutor;
34-
import com.google.common.annotations.VisibleForTesting;
35-
import com.google.common.collect.ImmutableMap;
36-
import com.google.gson.Gson;
37-
import com.google.gson.JsonObject;
38-
import com.google.inject.Inject;
39-
import com.google.inject.Singleton;
40-
import lombok.Builder;
41-
import lombok.NonNull;
42-
import lombok.extern.slf4j.Slf4j;
4343
import org.eclipse.lsp4j.*;
4444
import org.eclipse.lsp4j.jsonrpc.messages.Either;
4545
import org.eclipse.lsp4j.services.TextDocumentService;
@@ -69,7 +69,9 @@
6969
@Slf4j
7070
@Singleton
7171
public class CobolTextDocumentService
72-
implements TextDocumentService, EventObserver<RunAnalysisEvent>, DisposableService,
72+
implements TextDocumentService,
73+
EventObserver<RunAnalysisEvent>,
74+
DisposableService,
7375
ExtendedApiService {
7476
private static final List<String> COBOL_IDS = Arrays.asList("cobol", "cbl", "cob");
7577
private static final String GIT_FS_URI = "gitfs:/";
@@ -140,17 +142,6 @@ public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completio
140142
reportExceptionIfThrown(createDescriptiveErrorMessage("completion lookup", uri)));
141143
}
142144

143-
@Override
144-
@CheckServerShutdownState
145-
public CompletableFuture<CompletionItem> resolveCompletionItem(CompletionItem unresolved) {
146-
return supplyAsync(
147-
() -> completions.resolveDocumentationFor(unresolved),
148-
executors.getThreadPoolExecutor())
149-
.whenComplete(
150-
reportExceptionIfThrown(
151-
createDescriptiveErrorMessage("completion resolving", unresolved.getLabel())));
152-
}
153-
154145
@Override
155146
@CheckServerShutdownState
156147
public CompletableFuture<List<? extends Location>> definition(
@@ -270,21 +261,24 @@ public CompletableFuture<AnalysisResult> analysis(@NonNull JsonObject json) {
270261
AnalysisResultEvent event = new Gson().fromJson(json.toString(), AnalysisResultEvent.class);
271262
String uri = Optional.ofNullable(event).map(AnalysisResultEvent::getUri).orElse("");
272263
return CompletableFuture.supplyAsync(
273-
() -> Optional.ofNullable(docs.get(uri))
274-
.map(CobolDocumentModel::getAnalysisResult)
275-
.orElse(null),
276-
executors.getThreadPoolExecutor())
264+
() ->
265+
Optional.ofNullable(docs.get(uri))
266+
.map(CobolDocumentModel::getAnalysisResult)
267+
.orElse(null),
268+
executors.getThreadPoolExecutor())
277269
.whenComplete(
278270
reportExceptionIfThrown(createDescriptiveErrorMessage("analysis retrieving", uri)));
279271
}
280272

281273
private void registerEngineAndAnalyze(String uri, String text) {
282274
String fileExtension = extractExtension(uri);
283275
if (fileExtension != null && !isCobolFile(fileExtension)) {
284-
outlineMap.computeIfPresent(uri, (k, v) -> {
285-
v.complete(Collections.singletonList(new DocumentSymbol()));
286-
return v;
287-
});
276+
outlineMap.computeIfPresent(
277+
uri,
278+
(k, v) -> {
279+
v.complete(Collections.singletonList(new DocumentSymbol()));
280+
return v;
281+
});
288282
communications.notifyThatExtensionIsUnsupported(fileExtension);
289283
} else {
290284
communications.notifyThatLoadingInProgress(uri);
@@ -407,11 +401,9 @@ public CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> docume
407401
public CompletableFuture<Hover> hover(TextDocumentPositionParams position) {
408402
String uri = position.getTextDocument().getUri();
409403
return CompletableFuture.<Hover>supplyAsync(
410-
() -> hoverProvider.getHover(docs.get(uri), position),
411-
executors.getThreadPoolExecutor())
412-
.whenComplete(
413-
reportExceptionIfThrown(createDescriptiveErrorMessage("getting hover", uri)));
414-
404+
() -> hoverProvider.getHover(docs.get(uri), position),
405+
executors.getThreadPoolExecutor())
406+
.whenComplete(reportExceptionIfThrown(createDescriptiveErrorMessage("getting hover", uri)));
415407
}
416408

417409
private void registerDocument(String uri, CobolDocumentModel document) {

server/src/main/java/org/eclipse/lsp/cobol/service/delegates/completions/Completion.java

+5-47
Original file line numberDiff line numberDiff line change
@@ -14,70 +14,28 @@
1414
*/
1515
package org.eclipse.lsp.cobol.service.delegates.completions;
1616

17+
import lombok.NonNull;
1718
import org.eclipse.lsp.cobol.service.CobolDocumentModel;
1819
import org.eclipse.lsp4j.CompletionItem;
19-
import org.eclipse.lsp4j.CompletionItemKind;
2020

21-
import lombok.NonNull;
2221
import javax.annotation.Nullable;
2322
import java.util.Collection;
2423

2524
/**
2625
* Completion provider that allows to resolve autocomplete requests with specific items based on
2726
* type. The type of completion items may be dynamic (depends on the current document) and static
2827
* (does not depend on the document).
29-
*
30-
* <p>Use getSortOrderPrefix() to specify the order of the completions. It should go from dynamic to
31-
* static, from the most common the most rare.
3228
*/
3329
public interface Completion {
3430

3531
/**
36-
* Retrieve a collection of string that are going to be converted into completion items. Use
37-
* document to retrieve dynamic data or some special stuff for static data.
32+
* Provide a list of completion items of specific kind
3833
*
34+
* @param token - token to filter the suggestions
3935
* @param document - object that contains text and analysis output
4036
* @return collection of strings to be converted into completion items
4137
*/
4238
@NonNull
43-
Collection<String> getCompletionSource(@Nullable CobolDocumentModel document);
44-
45-
/**
46-
* Try to resolve the documentation for the completion item by its label
47-
*
48-
* @param label - A code part user typed in the IDE to be completed
49-
* @return the description for the label or null if not resolved
50-
*/
51-
@Nullable
52-
default String tryResolve(@NonNull String label) {
53-
return null;
54-
}
55-
56-
/**
57-
* Get a prefix for the completion item to apply sort with the expected order
58-
*
59-
* @return a string containing number for proper sorting
60-
*/
61-
@NonNull
62-
String getSortOrderPrefix();
63-
64-
/**
65-
* Get kind for the completion items to add specific icons on the client side.
66-
*
67-
* @return CompletionItemKind for the provided completions
68-
*/
69-
@NonNull
70-
CompletionItemKind getKind();
71-
72-
/**
73-
* Set special values to the given item if it is needed. Return the given element with no changes
74-
* by default
75-
*
76-
* @param item - a CompletionItem to be customized
77-
* @return a CompletionItem item with some special values set or the given item in the other case
78-
*/
79-
@NonNull
80-
default CompletionItem customize(@NonNull CompletionItem item) {
81-
return item;
82-
}
39+
Collection<CompletionItem> getCompletionItems(
40+
@NonNull String token, @Nullable CobolDocumentModel document);
8341
}

server/src/main/java/org/eclipse/lsp/cobol/service/delegates/completions/CompletionStorage.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import java.util.Set;
2525
import java.util.stream.Collectors;
2626

27+
/**
28+
* This class represents a storage for static completion content, e.g. keywords. It provides
29+
* elements as strings and documentation for them if provided.
30+
*/
2731
@Slf4j
2832
public abstract class CompletionStorage {
2933
private Map<String, String> storage = new HashMap<>();
@@ -67,11 +71,10 @@ private void fillInStorage(Properties props) {
6771
entry -> processDescription(entry.getValue().toString())));
6872
}
6973
/**
70-
* If description consist of several rows, then line breaks symbols should be replaced with actual
71-
* ones.
74+
* Replace line break tags with actual line breaks
7275
*
73-
* @param desc - Raw description retrieved from storage
74-
* @return THe description properly split in lines
76+
* @param desc - raw description retrieved from storage
77+
* @return the description properly split in lines
7578
*/
7679
private String processDescription(String desc) {
7780
return desc.replace("<br>", "\r\n\r\n");

server/src/main/java/org/eclipse/lsp/cobol/service/delegates/completions/Completions.java

+13-73
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,23 @@
1414
*/
1515
package org.eclipse.lsp.cobol.service.delegates.completions;
1616

17-
import org.eclipse.lsp.cobol.domain.modules.ServiceModule;
18-
import org.eclipse.lsp.cobol.service.CobolDocumentModel;
1917
import com.google.inject.Inject;
2018
import com.google.inject.Singleton;
19+
import lombok.NonNull;
2120
import lombok.extern.slf4j.Slf4j;
21+
import org.eclipse.lsp.cobol.domain.modules.ServiceModule;
22+
import org.eclipse.lsp.cobol.service.CobolDocumentModel;
2223
import org.eclipse.lsp4j.CompletionItem;
2324
import org.eclipse.lsp4j.CompletionList;
2425
import org.eclipse.lsp4j.CompletionParams;
25-
import org.eclipse.lsp4j.MarkupContent;
2626

27-
import lombok.NonNull;
2827
import javax.annotation.Nullable;
28+
import java.util.Collection;
2929
import java.util.List;
30-
import java.util.Objects;
3130
import java.util.Optional;
3231
import java.util.Set;
33-
import java.util.function.Function;
34-
import java.util.function.Predicate;
35-
import java.util.stream.Collectors;
32+
33+
import static java.util.stream.Collectors.toList;
3634

3735
/**
3836
* This class is used as a delegate for code completion operations. It requires type-specific
@@ -57,11 +55,9 @@ public class Completions {
5755
}
5856

5957
/**
60-
* Collect completion suggestions for a token in the document. The documentation for the
61-
* completion suggestion is not resolving in order to speed-up the autocomplete request
62-
* processing, so the list to return is marked as Incomplete. Use resolveDocumentationFor() to
63-
* fill-in the documentation. Document may be null if the request is invoked before the didOpen()
64-
* request was resolved and the document model is not stored on the server yet.
58+
* Collect completion suggestions for a token in the document. Document may be null if the request
59+
* is invoked before the didOpen() request has been resolved, and the document model is not stored
60+
* on the server yet.
6561
*
6662
* @param document - document model that should be used to retrieve the required token. May be
6763
* null.
@@ -72,50 +68,17 @@ public class Completions {
7268
@NonNull
7369
public CompletionList collectFor(
7470
@Nullable CobolDocumentModel document, @NonNull CompletionParams params) {
75-
return new CompletionList(true, collectCompletions(document, params));
76-
}
77-
78-
/**
79-
* Fills in the documentation for CompletionItem by its label. The documentation is marked-up
80-
* using a Markdown notation. If there is no documentation could be provided, then the
81-
* documentation is a {@link MarkupContent} with null as a value.
82-
*
83-
* @param unresolved - CompletionItem to be resolved
84-
* @return the given CompletionItem with resolved documentation
85-
*/
86-
@NonNull
87-
public CompletionItem resolveDocumentationFor(@NonNull CompletionItem unresolved) {
88-
unresolved.setDocumentation(
89-
wrapWithMarkup(
90-
providers.stream()
91-
.map(it -> it.tryResolve(unresolved.getLabel()))
92-
.filter(Objects::nonNull)
93-
.findAny()
94-
.orElse(null)));
95-
96-
return unresolved;
97-
}
98-
99-
@NonNull
100-
private MarkupContent wrapWithMarkup(@Nullable String desc) {
101-
MarkupContent markupContent = new MarkupContent();
102-
markupContent.setKind("markdown");
103-
markupContent.setValue(desc);
104-
return markupContent;
71+
return new CompletionList(false, collectCompletions(document, params));
10572
}
10673

10774
@NonNull
10875
private List<CompletionItem> collectCompletions(
10976
@Nullable CobolDocumentModel document, @NonNull CompletionParams params) {
110-
String token = retrieveToken(document, params);
11177
return providers
11278
.parallelStream()
113-
.flatMap(
114-
it ->
115-
it.getCompletionSource(document).stream()
116-
.filter(startsWithIgnoreCase(token))
117-
.map(convertToCompletionItem(it)))
118-
.collect(Collectors.toList());
79+
.map(it -> it.getCompletionItems(retrieveToken(document, params), document))
80+
.flatMap(Collection::stream)
81+
.collect(toList());
11982
}
12083

12184
@NonNull
@@ -125,27 +88,4 @@ private String retrieveToken(
12588
.map(it -> it.getTokenBeforePosition(params.getPosition()))
12689
.orElse("");
12790
}
128-
/**
129-
* Returns predicate which may be used to filter strings that starts with a given string ignoring
130-
* case. Code example: list.stream().filter(CompletionUtils.startsWithIgnoreCase("string");
131-
*
132-
* @param token - The string that the checking string should start with
133-
* @return Predicate that may be used in Stream.filter()
134-
*/
135-
@NonNull
136-
private Predicate<String> startsWithIgnoreCase(@NonNull String token) {
137-
return word -> word.regionMatches(true, 0, token, 0, token.length());
138-
}
139-
140-
@NonNull
141-
private Function<String, CompletionItem> convertToCompletionItem(@NonNull Completion it) {
142-
return word -> {
143-
CompletionItem item = new CompletionItem();
144-
item.setLabel(word);
145-
item.setInsertText(word);
146-
item.setKind(it.getKind());
147-
item.setSortText(it.getSortOrderPrefix() + word);
148-
return it.customize(item);
149-
};
150-
}
15191
}

0 commit comments

Comments
 (0)