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.io.File;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -128,7 +126,7 @@ public class SpringSymbolIndex implements InitializingBean {
|
|||||||
private String watchXMLChangedRegistration;
|
private String watchXMLChangedRegistration;
|
||||||
|
|
||||||
// Futures resolved when project is initialized/indexed
|
// 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() {
|
private SimpleWorkspaceService getWorkspaceService() {
|
||||||
@@ -538,61 +536,52 @@ public class SpringSymbolIndex implements InitializingBean {
|
|||||||
.map(enhanced -> enhanced.getSymbol());
|
.map(enhanced -> enhanced.getSymbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized private CompletableFuture<Void> projectInitializedFuture(IJavaProject project) {
|
synchronized private CompletableFuture<IJavaProject> projectInitializedFuture(IJavaProject project) {
|
||||||
if (project == null) {
|
if (project == null) {
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
} else {
|
} else {
|
||||||
URI uri = project.getLocationUri();
|
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) {
|
public List<? extends SymbolInformation> getSymbols(String docURI) {
|
||||||
try {
|
try {
|
||||||
|
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docURI);
|
||||||
URI uri = URI.create(docURI);
|
URI uri = URI.create(docURI);
|
||||||
|
CompletableFuture<IJavaProject> projectInitialized = futureProjectFinder.findFuture(uri).thenCompose(project -> projectInitializedFuture(project));
|
||||||
/*
|
IJavaProject project = projectInitialized.get(15, TimeUnit.SECONDS);
|
||||||
* Workaround for docUri coming from vscode-languageclient on Windows
|
ImmutableList.Builder<SymbolInformation> builder = ImmutableList.builder();
|
||||||
*
|
if (project != null && doc != null) {
|
||||||
* It comes in as "file:///c%3A/Users/ab/spring-petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java"
|
// Collect symbols from the opened document
|
||||||
*
|
for (SpringIndexer indexer : this.indexers) {
|
||||||
* While symbols index would have this uri instead:
|
if (indexer.isInterestedIn(docURI)) {
|
||||||
* - "file:///C:/Users/ab/spring-petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java"
|
try {
|
||||||
*
|
for (EnhancedSymbolInformation enhanced : indexer.computeSymbols(project, docURI,
|
||||||
* i.e. lower vs upper case drive letter and escaped drive colon
|
doc.get())) {
|
||||||
*/
|
builder.add(enhanced.getSymbol());
|
||||||
if ("file".equals(uri.getScheme())) {
|
}
|
||||||
String path = URLDecoder.decode(uri.getPath(), StandardCharsets.UTF_8);
|
} catch (Exception e) {
|
||||||
int colonIdx = path.indexOf(':');
|
log.error("{}", e);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uri = UriUtil.toUri(new File(path));
|
} else {
|
||||||
}
|
// Take symbols from the index if there is no opened document.
|
||||||
|
List<EnhancedSymbolInformation> docSymbols = this.symbolsByDoc.get(uri.toString());
|
||||||
CompletableFuture<Void> projectInitialized = futureProjectFinder.findFuture(uri).thenCompose(project -> projectInitializedFuture(project));
|
if (docSymbols != null) {
|
||||||
projectInitialized.get(15, TimeUnit.SECONDS);
|
synchronized (docSymbols) {
|
||||||
List<EnhancedSymbolInformation> docSymbols = this.symbolsByDoc.get(uri.toString());
|
for (EnhancedSymbolInformation enhanced : docSymbols) {
|
||||||
if (docSymbols != null) {
|
builder.add(enhanced.getSymbol());
|
||||||
synchronized (docSymbols) {
|
}
|
||||||
ImmutableList.Builder<SymbolInformation> builder = ImmutableList.builder();
|
|
||||||
for (EnhancedSymbolInformation enhanced : docSymbols) {
|
|
||||||
builder.add(enhanced.getSymbol());
|
|
||||||
}
|
}
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return builder.build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("", e);
|
log.warn("", e);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SymbolAddOnInformation> getAllAdditionalInformation(Predicate<SymbolAddOnInformation> filter) {
|
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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
@@ -33,4 +33,9 @@ public class EnhancedSymbolInformation {
|
|||||||
return additionalInformation;
|
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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
@@ -36,4 +36,10 @@ public class CachedSymbol {
|
|||||||
return lastModified;
|
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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
@@ -10,6 +10,9 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.springframework.ide.vscode.boot.java.utils;
|
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;
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,6 +22,8 @@ public interface SpringIndexer {
|
|||||||
|
|
||||||
String[] getFileWatchPatterns();
|
String[] getFileWatchPatterns();
|
||||||
boolean isInterestedIn(String docURI);
|
boolean isInterestedIn(String docURI);
|
||||||
|
|
||||||
|
List<EnhancedSymbolInformation> computeSymbols(IJavaProject project, String docURI, String content) throws Exception;
|
||||||
|
|
||||||
void initializeProject(IJavaProject project) throws Exception;
|
void initializeProject(IJavaProject project) throws Exception;
|
||||||
void removeProject(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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
@@ -19,6 +19,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -230,6 +231,35 @@ public class SpringIndexerJava implements SpringIndexer {
|
|||||||
scanAffectedFiles(project, context.getScannedTypes(), scannedFiles);
|
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 {
|
private Set<String> scanFilesInternally(IJavaProject project, DocumentDescriptor[] docs) throws Exception {
|
||||||
ASTParser parser = createParser(project, false);
|
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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
@@ -17,6 +17,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -30,6 +31,7 @@ import org.eclipse.lemminx.dom.DOMNode;
|
|||||||
import org.eclipse.lemminx.dom.DOMParser;
|
import org.eclipse.lemminx.dom.DOMParser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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.IClasspath;
|
||||||
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
||||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
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,
|
Event,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
ProviderResult,
|
ProviderResult,
|
||||||
TextDocument
|
TextDocument,
|
||||||
|
Uri
|
||||||
} from "vscode";
|
} from "vscode";
|
||||||
import {HighlightParams, toVSRange} from './highlight-service';
|
import {HighlightParams, toVSRange} from './highlight-service';
|
||||||
import * as Lsp from 'vscode-languageclient';
|
import * as Lsp from 'vscode-languageclient';
|
||||||
@@ -22,7 +23,7 @@ export class HighlightCodeLensProvider implements CodeLensProvider {
|
|||||||
|
|
||||||
handle(highlghtParams: HighlightParams) {
|
handle(highlghtParams: HighlightParams) {
|
||||||
if (!deepEqual(this.highlights.get(highlghtParams.doc.uri), highlghtParams)) {
|
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();
|
this._onDidChangeCodeLenses.fire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export class HighlightService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle(params : HighlightParams) : void {
|
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);
|
this.refresh(params.doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ export class HighlightService {
|
|||||||
for (let editor of editors) {
|
for (let editor of editors) {
|
||||||
const activeUri = editor.document.uri.toString();
|
const activeUri = editor.document.uri.toString();
|
||||||
const activeVersion = editor.document.version;
|
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
|
//We only update highlights in the active editor for now
|
||||||
this.updateHighlightsForEditor(editor);
|
this.updateHighlightsForEditor(editor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import * as OS from "os";
|
||||||
import * as VSCode from 'vscode';
|
import * as VSCode from 'vscode';
|
||||||
import { workspace } 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"),
|
workspaceOptions: VSCode.workspace.getConfiguration("spring-boot.ls"),
|
||||||
clientOptions: {
|
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
|
// 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: [ PROPERTIES_LANGUAGE_ID, YAML_LANGUAGE_ID, JAVA_LANGUAGE_ID ],
|
||||||
documentSelector: [
|
documentSelector: [
|
||||||
|
|||||||
Reference in New Issue
Block a user