Skip to content

Commit 30e132b

Browse files
authored
Merge pull request #2882 from 1c-syntax/feature/report-progress
Показ прогресса иницициализации контекста
2 parents 21cb3b2 + 0d1a290 commit 30e132b

File tree

6 files changed

+400
-18
lines changed

6 files changed

+400
-18
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2022
5+
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package com.github._1c_syntax.bsl.languageserver;
23+
24+
import lombok.AllArgsConstructor;
25+
import lombok.RequiredArgsConstructor;
26+
import lombok.Setter;
27+
import org.eclipse.lsp4j.ClientCapabilities;
28+
import org.eclipse.lsp4j.ProgressParams;
29+
import org.eclipse.lsp4j.WindowClientCapabilities;
30+
import org.eclipse.lsp4j.WorkDoneProgressBegin;
31+
import org.eclipse.lsp4j.WorkDoneProgressCreateParams;
32+
import org.eclipse.lsp4j.WorkDoneProgressEnd;
33+
import org.eclipse.lsp4j.WorkDoneProgressReport;
34+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
35+
import org.eclipse.lsp4j.services.LanguageClient;
36+
import org.springframework.stereotype.Component;
37+
38+
import java.util.UUID;
39+
import java.util.concurrent.atomic.AtomicInteger;
40+
41+
@Component
42+
@RequiredArgsConstructor
43+
public class WorkDoneProgressHelper {
44+
45+
private final LanguageClientHolder languageClientHolder;
46+
private final ClientCapabilitiesHolder clientCapabilitiesHolder;
47+
48+
private boolean isWorkDoneProgressSupported;
49+
50+
public WorkDoneProgressReporter createProgress(int size, String messagePostfix) {
51+
isWorkDoneProgressSupported = clientCapabilitiesHolder.getCapabilities()
52+
.map(ClientCapabilities::getWindow)
53+
.map(WindowClientCapabilities::getWorkDoneProgress)
54+
.orElse(false);
55+
56+
if (!isWorkDoneProgressSupported) {
57+
return new WorkDoneProgressReporter("", 0, "");
58+
}
59+
60+
var token = UUID.randomUUID().toString();
61+
var createProgressParams = new WorkDoneProgressCreateParams(Either.forLeft(token));
62+
63+
languageClientHolder.execIfConnected(languageClient ->
64+
languageClient.createProgress(createProgressParams)
65+
);
66+
67+
return new WorkDoneProgressReporter(token, size, messagePostfix);
68+
}
69+
70+
71+
@AllArgsConstructor
72+
public class WorkDoneProgressReporter {
73+
private final String token;
74+
@Setter
75+
private int size;
76+
private final String messagePostfix;
77+
78+
private final AtomicInteger counter = new AtomicInteger();
79+
80+
public void beginProgress(String title) {
81+
if (!isWorkDoneProgressSupported) {
82+
return;
83+
}
84+
85+
languageClientHolder.execIfConnected((LanguageClient languageClient) -> {
86+
var value = new WorkDoneProgressBegin();
87+
value.setTitle(title);
88+
89+
var params = new ProgressParams(Either.forLeft(token), Either.forLeft(value));
90+
languageClient.notifyProgress(params);
91+
});
92+
}
93+
94+
public void tick(String message, int percentage) {
95+
if (!isWorkDoneProgressSupported) {
96+
return;
97+
}
98+
99+
languageClientHolder.execIfConnected((LanguageClient languageClient) -> {
100+
var value = new WorkDoneProgressReport();
101+
value.setMessage(message);
102+
value.setCancellable(false);
103+
value.setPercentage(percentage);
104+
105+
var params = new ProgressParams(Either.forLeft(token), Either.forLeft(value));
106+
languageClient.notifyProgress(params);
107+
});
108+
}
109+
110+
public void tick() {
111+
if (!isWorkDoneProgressSupported) {
112+
return;
113+
}
114+
115+
var currentCounter = counter.incrementAndGet();
116+
var message = String.format("%d/%d%s", currentCounter, size, messagePostfix);
117+
var percentage = currentCounter / size;
118+
119+
tick(message, percentage);
120+
}
121+
122+
public void endProgress(String message) {
123+
if (!isWorkDoneProgressSupported) {
124+
return;
125+
}
126+
127+
languageClientHolder.execIfConnected((LanguageClient languageClient) -> {
128+
var value = new WorkDoneProgressEnd();
129+
value.setMessage(message);
130+
131+
var params = new ProgressParams(Either.forLeft(token), Either.forLeft(value));
132+
languageClient.notifyProgress(params);
133+
});
134+
}
135+
}
136+
}

src/main/java/com/github/_1c_syntax/bsl/languageserver/cli/AnalyzeCommand.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import java.nio.file.Path;
4646
import java.time.LocalDateTime;
4747
import java.util.ArrayList;
48-
import java.util.Collection;
4948
import java.util.List;
5049
import java.util.Optional;
5150
import java.util.concurrent.Callable;
@@ -167,7 +166,7 @@ public Integer call() {
167166
var configurationPath = LanguageServerConfiguration.getCustomConfigurationRoot(configuration, srcDir);
168167
context.setConfigurationRoot(configurationPath);
169168

170-
Collection<File> files = FileUtils.listFiles(srcDir.toFile(), new String[]{"bsl", "os"}, true);
169+
var files = (List<File>) FileUtils.listFiles(srcDir.toFile(), new String[]{"bsl", "os"}, true);
171170

172171
context.populateContext(files);
173172

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
*/
2222
package com.github._1c_syntax.bsl.languageserver.context;
2323

24+
import com.github._1c_syntax.bsl.languageserver.WorkDoneProgressHelper;
25+
import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
2426
import com.github._1c_syntax.bsl.languageserver.utils.MdoRefBuilder;
27+
import com.github._1c_syntax.bsl.languageserver.utils.Resources;
2528
import com.github._1c_syntax.bsl.types.ModuleType;
2629
import com.github._1c_syntax.mdclasses.Configuration;
2730
import com.github._1c_syntax.utils.Absolute;
@@ -32,18 +35,18 @@
3235
import lombok.extern.slf4j.Slf4j;
3336
import org.apache.commons.io.FileUtils;
3437
import org.eclipse.lsp4j.TextDocumentItem;
35-
import org.springframework.beans.factory.annotation.Lookup;
38+
import org.springframework.beans.factory.ObjectProvider;
3639
import org.springframework.stereotype.Component;
3740

3841
import javax.annotation.CheckForNull;
3942
import java.io.File;
4043
import java.net.URI;
4144
import java.nio.charset.StandardCharsets;
4245
import java.nio.file.Path;
43-
import java.util.Collection;
4446
import java.util.Collections;
4547
import java.util.EnumMap;
4648
import java.util.HashMap;
49+
import java.util.List;
4750
import java.util.Map;
4851
import java.util.Optional;
4952
import java.util.concurrent.ExecutionException;
@@ -54,7 +57,11 @@
5457
@Slf4j
5558
@Component
5659
@RequiredArgsConstructor
57-
public abstract class ServerContext {
60+
public class ServerContext {
61+
private final ObjectProvider<DocumentContext> documentContextProvider;
62+
private final WorkDoneProgressHelper workDoneProgressHelper;
63+
private final LanguageServerConfiguration languageServerConfiguration;
64+
5865
private final Map<URI, DocumentContext> documents = Collections.synchronizedMap(new HashMap<>());
5966
private final Lazy<Configuration> configurationMetadata = new Lazy<>(this::computeConfigurationMetadata);
6067
@CheckForNull
@@ -70,29 +77,42 @@ public void populateContext() {
7077
LOGGER.info("Can't populate server context. Configuration root is not defined.");
7178
return;
7279
}
80+
81+
var workDoneProgressReporter = workDoneProgressHelper.createProgress(0, "");
82+
workDoneProgressReporter.beginProgress(getMessage("populateFindFiles"));
83+
7384
LOGGER.debug("Finding files to populate context...");
74-
Collection<File> files = FileUtils.listFiles(
85+
var files = (List<File>) FileUtils.listFiles(
7586
configurationRoot.toFile(),
7687
new String[]{"bsl", "os"},
7788
true
7889
);
90+
workDoneProgressReporter.endProgress("");
7991
populateContext(files);
8092
}
8193

82-
public void populateContext(Collection<File> uris) {
94+
public void populateContext(List<File> files) {
95+
var workDoneProgressReporter = workDoneProgressHelper.createProgress(files.size(), getMessage("populateFilesPostfix"));
96+
workDoneProgressReporter.beginProgress(getMessage("populatePopulatingContext"));
97+
8398
LOGGER.debug("Populating context...");
8499
contextLock.writeLock().lock();
85100

86-
uris.parallelStream().forEach((File file) -> {
101+
files.parallelStream().forEach((File file) -> {
102+
103+
workDoneProgressReporter.tick();
104+
87105
var documentContext = getDocument(file.toURI());
88106
if (documentContext == null) {
89-
documentContext = createDocumentContext(file, 0);
107+
documentContext = createDocumentContext(file);
90108
documentContext.freezeComputedData();
91109
documentContext.clearSecondaryData();
92110
}
93111
});
94112

95113
contextLock.writeLock().unlock();
114+
115+
workDoneProgressReporter.endProgress(getMessage("populateContextPopulated"));
96116
LOGGER.debug("Context populated.");
97117
}
98118

@@ -146,7 +166,7 @@ public DocumentContext addDocument(TextDocumentItem textDocumentItem) {
146166
}
147167

148168
public void removeDocument(URI uri) {
149-
URI absoluteURI = Absolute.uri(uri);
169+
var absoluteURI = Absolute.uri(uri);
150170
removeDocumentMdoRefByUri(absoluteURI);
151171
documents.remove(absoluteURI);
152172
}
@@ -162,19 +182,16 @@ public Configuration getConfiguration() {
162182
return configurationMetadata.getOrCompute();
163183
}
164184

165-
@Lookup
166-
protected abstract DocumentContext lookupDocumentContext(URI absoluteURI);
167-
168185
@SneakyThrows
169-
private DocumentContext createDocumentContext(File file, int version) {
170-
String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
171-
return createDocumentContext(file.toURI(), content, version);
186+
private DocumentContext createDocumentContext(File file) {
187+
var content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
188+
return createDocumentContext(file.toURI(), content, 0);
172189
}
173190

174191
private DocumentContext createDocumentContext(URI uri, String content, int version) {
175-
URI absoluteURI = Absolute.uri(uri);
192+
var absoluteURI = Absolute.uri(uri);
176193

177-
var documentContext = lookupDocumentContext(absoluteURI);
194+
var documentContext = documentContextProvider.getObject(absoluteURI);
178195
documentContext.rebuild(content, version);
179196

180197
documents.put(absoluteURI, documentContext);
@@ -188,6 +205,9 @@ private Configuration computeConfigurationMetadata() {
188205
return Configuration.create();
189206
}
190207

208+
var progress = workDoneProgressHelper.createProgress(0, "");
209+
progress.beginProgress(getMessage("computeConfigurationMetadata"));
210+
191211
Configuration configuration;
192212
var executorService = Executors.newCachedThreadPool();
193213
try {
@@ -203,6 +223,8 @@ private Configuration computeConfigurationMetadata() {
203223
executorService.shutdown();
204224
}
205225

226+
progress.endProgress(getMessage("computeConfigurationMetadataDone"));
227+
206228
return configuration;
207229
}
208230

@@ -229,4 +251,8 @@ private void removeDocumentMdoRefByUri(URI uri) {
229251
mdoRefs.remove(uri);
230252
}
231253
}
254+
255+
private String getMessage(String key) {
256+
return Resources.getResourceString(languageServerConfiguration.getLanguage(), getClass(), key);
257+
}
232258
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
computeConfigurationMetadata=Computing configuration metadata...
2+
computeConfigurationMetadataDone=Configuration metadata computing is finished.
3+
populateContextPopulated=Context populated.
4+
populateFindFiles=Finding files to populate context...
5+
populatePopulatingContext=Populating context...
6+
populateFilesPostfix=\ files
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
populateContextPopulated=Наполнение контекста завершено.
2+
populateFindFiles=Ищем файлы для наполнения контекста...
3+
populatePopulatingContext=Наполняем контекст...
4+
computeConfigurationMetadata=Рассчитываем данные конфигурации...
5+
computeConfigurationMetadataDone=Расчет метаданных конфигурации завершен.
6+
populateFilesPostfix=\ файлов

0 commit comments

Comments
 (0)