Doc Symbols proper support
This commit is contained in:
@@ -13,8 +13,6 @@ package org.springframework.ide.vscode.boot.app;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -128,7 +126,7 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
private String watchXMLChangedRegistration;
|
||||
|
||||
// Futures resolved when project is initialized/indexed
|
||||
private Map<URI, CompletableFuture<Void>> initializedProjects = new HashMap<>();
|
||||
private Map<URI, CompletableFuture<IJavaProject>> initializedProjects = new HashMap<>();
|
||||
|
||||
|
||||
private SimpleWorkspaceService getWorkspaceService() {
|
||||
@@ -538,61 +536,52 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
.map(enhanced -> enhanced.getSymbol());
|
||||
}
|
||||
|
||||
synchronized private CompletableFuture<Void> projectInitializedFuture(IJavaProject project) {
|
||||
synchronized private CompletableFuture<IJavaProject> projectInitializedFuture(IJavaProject project) {
|
||||
if (project == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
URI uri = project.getLocationUri();
|
||||
return initializedProjects.computeIfAbsent(uri, u -> new CompletableFuture<Void>());
|
||||
return initializedProjects.computeIfAbsent(uri, u -> CompletableFuture.completedFuture(project));
|
||||
}
|
||||
}
|
||||
|
||||
public List<? extends SymbolInformation> getSymbols(String docURI) {
|
||||
try {
|
||||
try {
|
||||
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docURI);
|
||||
URI uri = URI.create(docURI);
|
||||
|
||||
/*
|
||||
* Workaround for docUri coming from vscode-languageclient on Windows
|
||||
*
|
||||
* It comes in as "file:///c%3A/Users/ab/spring-petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java"
|
||||
*
|
||||
* While symbols index would have this uri instead:
|
||||
* - "file:///C:/Users/ab/spring-petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java"
|
||||
*
|
||||
* i.e. lower vs upper case drive letter and escaped drive colon
|
||||
*/
|
||||
if ("file".equals(uri.getScheme())) {
|
||||
String path = URLDecoder.decode(uri.getPath(), StandardCharsets.UTF_8);
|
||||
int colonIdx = path.indexOf(':');
|
||||
if (colonIdx > 0 && colonIdx < 3) {
|
||||
int driveIdx = colonIdx - 1;
|
||||
if (Character.isLowerCase(path.charAt(driveIdx))) {
|
||||
StringBuilder sb = new StringBuilder(path.substring(0, driveIdx));
|
||||
sb.append(Character.toUpperCase(path.charAt(driveIdx)));
|
||||
sb.append(path.substring(driveIdx + 1));
|
||||
path = sb.toString();
|
||||
CompletableFuture<IJavaProject> projectInitialized = futureProjectFinder.findFuture(uri).thenCompose(project -> projectInitializedFuture(project));
|
||||
IJavaProject project = projectInitialized.get(15, TimeUnit.SECONDS);
|
||||
ImmutableList.Builder<SymbolInformation> builder = ImmutableList.builder();
|
||||
if (project != null && doc != null) {
|
||||
// Collect symbols from the opened document
|
||||
for (SpringIndexer indexer : this.indexers) {
|
||||
if (indexer.isInterestedIn(docURI)) {
|
||||
try {
|
||||
for (EnhancedSymbolInformation enhanced : indexer.computeSymbols(project, docURI,
|
||||
doc.get())) {
|
||||
builder.add(enhanced.getSymbol());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
uri = UriUtil.toUri(new File(path));
|
||||
}
|
||||
|
||||
CompletableFuture<Void> projectInitialized = futureProjectFinder.findFuture(uri).thenCompose(project -> projectInitializedFuture(project));
|
||||
projectInitialized.get(15, TimeUnit.SECONDS);
|
||||
List<EnhancedSymbolInformation> docSymbols = this.symbolsByDoc.get(uri.toString());
|
||||
if (docSymbols != null) {
|
||||
synchronized (docSymbols) {
|
||||
ImmutableList.Builder<SymbolInformation> builder = ImmutableList.builder();
|
||||
for (EnhancedSymbolInformation enhanced : docSymbols) {
|
||||
builder.add(enhanced.getSymbol());
|
||||
} else {
|
||||
// Take symbols from the index if there is no opened document.
|
||||
List<EnhancedSymbolInformation> docSymbols = this.symbolsByDoc.get(uri.toString());
|
||||
if (docSymbols != null) {
|
||||
synchronized (docSymbols) {
|
||||
for (EnhancedSymbolInformation enhanced : docSymbols) {
|
||||
builder.add(enhanced.getSymbol());
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
} catch (Exception e) {
|
||||
log.warn("", e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public List<SymbolAddOnInformation> getAllAdditionalInformation(Predicate<SymbolAddOnInformation> filter) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2022 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -33,4 +33,9 @@ public class EnhancedSymbolInformation {
|
||||
return additionalInformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnhancedSymbolInformation [symbol=" + symbol + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2019, 2022 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -36,4 +36,10 @@ public class CachedSymbol {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CachedSymbol [docURI=" + docURI + ", enhancedSymbol=" + enhancedSymbol + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2019, 2022 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -10,6 +10,9 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
/**
|
||||
@@ -19,6 +22,8 @@ public interface SpringIndexer {
|
||||
|
||||
String[] getFileWatchPatterns();
|
||||
boolean isInterestedIn(String docURI);
|
||||
|
||||
List<EnhancedSymbolInformation> computeSymbols(IJavaProject project, String docURI, String content) throws Exception;
|
||||
|
||||
void initializeProject(IJavaProject project) throws Exception;
|
||||
void removeProject(IJavaProject project) throws Exception;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2022 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -19,6 +19,7 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -230,6 +231,35 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
scanAffectedFiles(project, context.getScannedTypes(), scannedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
public List<EnhancedSymbolInformation> computeSymbols(IJavaProject project, String docURI, String content) throws Exception {
|
||||
ASTParser parser = createParser(project, false);
|
||||
|
||||
if (content != null) {
|
||||
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||
parser.setUnitName(unitName);
|
||||
log.debug("Scan file: {}", unitName);
|
||||
parser.setSource(content.toCharArray());
|
||||
|
||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
|
||||
if (cu != null) {
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
|
||||
AtomicReference<TextDocument> docRef = new AtomicReference<>();
|
||||
String file = UriUtil.toFileString(docURI);
|
||||
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, file,
|
||||
0, docRef, content, generatedSymbols, SCAN_PASS.ONE, new ArrayList<>());
|
||||
|
||||
scanAST(context);
|
||||
|
||||
return generatedSymbols.stream().map(s -> s.getEnhancedSymbol()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
|
||||
}
|
||||
|
||||
private Set<String> scanFilesInternally(IJavaProject project, DocumentDescriptor[] docs) throws Exception {
|
||||
ASTParser parser = createParser(project, false);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2019, 2022 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -17,6 +17,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -30,6 +31,7 @@ import org.eclipse.lemminx.dom.DOMNode;
|
||||
import org.eclipse.lemminx.dom.DOMParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
@@ -308,5 +310,16 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnhancedSymbolInformation> computeSymbols(IJavaProject project, String docURI, String content)
|
||||
throws Exception {
|
||||
if (content != null) {
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<>();
|
||||
scanFile(project, content, docURI, 0, generatedSymbols);
|
||||
return generatedSymbols.stream().map(s -> s.getEnhancedSymbol()).collect(Collectors.toList());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
Event,
|
||||
EventEmitter,
|
||||
ProviderResult,
|
||||
TextDocument
|
||||
TextDocument,
|
||||
Uri
|
||||
} from "vscode";
|
||||
import {HighlightParams, toVSRange} from './highlight-service';
|
||||
import * as Lsp from 'vscode-languageclient';
|
||||
@@ -22,7 +23,7 @@ export class HighlightCodeLensProvider implements CodeLensProvider {
|
||||
|
||||
handle(highlghtParams: HighlightParams) {
|
||||
if (!deepEqual(this.highlights.get(highlghtParams.doc.uri), highlghtParams)) {
|
||||
this.highlights.set(highlghtParams.doc.uri, highlghtParams);
|
||||
this.highlights.set(Uri.parse(highlghtParams.doc.uri).toString(), highlghtParams);
|
||||
this._onDidChangeCodeLenses.fire();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export class HighlightService {
|
||||
}
|
||||
|
||||
handle(params : HighlightParams) : void {
|
||||
this.highlights.set(params.doc.uri, params);
|
||||
this.highlights.set(VSCode.Uri.parse(params.doc.uri).toString(), params);
|
||||
this.refresh(params.doc);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export class HighlightService {
|
||||
for (let editor of editors) {
|
||||
const activeUri = editor.document.uri.toString();
|
||||
const activeVersion = editor.document.version;
|
||||
if (docId.uri === activeUri && docId.version === activeVersion) {
|
||||
if (VSCode.Uri.parse(docId.uri).toString() === activeUri && docId.version === activeVersion) {
|
||||
//We only update highlights in the active editor for now
|
||||
this.updateHighlightsForEditor(editor);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
import * as OS from "os";
|
||||
import * as VSCode from 'vscode';
|
||||
import { workspace } from 'vscode';
|
||||
|
||||
@@ -44,6 +45,30 @@ export function activate(context: VSCode.ExtensionContext): Thenable<LanguageCli
|
||||
},
|
||||
workspaceOptions: VSCode.workspace.getConfiguration("spring-boot.ls"),
|
||||
clientOptions: {
|
||||
uriConverters: {
|
||||
code2Protocol: (uri) => {
|
||||
/*
|
||||
* Workaround for docUri coming from vscode-languageclient on Windows
|
||||
*
|
||||
* It comes in as "file:///c%3A/Users/ab/spring-petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java"
|
||||
*
|
||||
* While symbols index would have this uri instead:
|
||||
* - "file:///C:/Users/ab/spring-petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java"
|
||||
*
|
||||
* i.e. lower vs upper case drive letter and escaped drive colon
|
||||
*/
|
||||
if (OS.platform() === "win32" && uri.scheme === 'file') {
|
||||
let uriStr = uri.toString(true);
|
||||
const idx = uriStr.indexOf(':', 5);
|
||||
if (idx > 5 && idx < 10) {
|
||||
uriStr = `${uriStr.substring(0, idx - 1)}${uriStr.charAt(idx - 1).toUpperCase()}${uriStr.substring(idx)}`
|
||||
}
|
||||
return uriStr;
|
||||
}
|
||||
return uri.toString();
|
||||
},
|
||||
protocol2Code: uri => VSCode.Uri.file(uri)
|
||||
},
|
||||
// See PT-158992999 as to why a scheme is added to the document selector
|
||||
// documentSelector: [ PROPERTIES_LANGUAGE_ID, YAML_LANGUAGE_ID, JAVA_LANGUAGE_ID ],
|
||||
documentSelector: [
|
||||
|
||||
Reference in New Issue
Block a user