Doc Symbols proper support

This commit is contained in:
BoykoAlex
2022-03-10 13:44:08 -05:00
committed by BoykoAlex
parent a588354ca9
commit d350da5992
9 changed files with 123 additions and 49 deletions

View File

@@ -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) {

View File

@@ -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 + "]";
}
}

View File

@@ -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 + "]";
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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: [