X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.ui%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fui%2Feditor%2Fcompletion%2FSCLTextEditorEnvironment.java;h=ffe709f45b768a9ff6c3cd5172b783fd349b5fa9;hp=1aebc06e817b52364cfe2794140a3e349ac37cd2;hb=9712014e959584157b02e594be8719c151b8f5b0;hpb=1b4d8b692f40d946deb5db8280eb4ca5b36a75a7 diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor/completion/SCLTextEditorEnvironment.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor/completion/SCLTextEditorEnvironment.java index 1aebc06e8..ffe709f45 100644 --- a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor/completion/SCLTextEditorEnvironment.java +++ b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor/completion/SCLTextEditorEnvironment.java @@ -1,172 +1,149 @@ -package org.simantics.scl.ui.editor.completion; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.contentassist.ICompletionProposal; -import org.simantics.scl.compiler.common.names.Name; -import org.simantics.scl.compiler.compilation.EnvironmentOfModule; -import org.simantics.scl.compiler.elaboration.modules.SCLValue; -import org.simantics.scl.compiler.environment.AmbiguousNameException; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.environment.Environments; -import org.simantics.scl.compiler.errors.Failable; -import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException; -import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl; -import org.simantics.scl.compiler.module.ImportDeclaration; -import org.simantics.scl.compiler.module.Module; -import org.simantics.scl.compiler.module.repository.ImportFailureException; -import org.simantics.scl.compiler.types.TCon; -import org.simantics.scl.osgi.SCLOsgi; - -public class SCLTextEditorEnvironment { - - private String moduleName; - private SCLCompletionProposal[] proposalCache = new SCLCompletionProposal[0]; - private List moduleProposalCache = new ArrayList<>(0); - private Environment env; - - private List cachedImports = new ArrayList<>(); - private boolean cacheUpdated = false; - - public SCLTextEditorEnvironment(String moduleName) { - this.moduleName = moduleName; - } - - public void updateModuleName(String moduleName) { - this.moduleName = moduleName; - } - - public void updateEnvironment(IDocument document) { - String contents = document.get(); - String[] lines = contents.split("\\R+"); - List imports = new ArrayList<>(); - imports.add(new ImportDeclaration("StandardLibrary", "")); - for (String line : lines) { - line = line.trim(); - if (line.startsWith("import") || line.startsWith("include")) { - SCLParserImpl parser = new SCLParserImpl(new StringReader(line)); - try { - ImportDeclaration importDecl = (ImportDeclaration)parser.parseImport(); - imports.add(importDecl); - } catch (SCLSyntaxErrorException e) { - // Import cannot be handled, ignore - } - } - } - - imports = processRelativeImports(imports); - if (!imports.equals(cachedImports)) { - cachedImports = imports; - try { - env = SCLOsgi.MODULE_REPOSITORY.createEnvironment(cachedImports.toArray(new ImportDeclaration[cachedImports.size()]), null); - Failable module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName); - if(module.didSucceed()) - env = new EnvironmentOfModule(env, module.getResult()); - } catch (ImportFailureException e) { - //e.printStackTrace(); - } - } - } - - public ICompletionProposal[] getCompletionProposals(String prefix, int offset) { - int p = prefix.lastIndexOf('.'); - String lastPart = p==-1 ? prefix : prefix.substring(p+1); - - List proposals = new ArrayList<>(); - for(SCLValue value : Environments.findValuesForPrefix(env, prefix)) { - Name name = value.getName(); - if((name.module.equals(moduleName) || !value.isPrivate()) && !(name.name.contains("$") && Character.isLetter(name.name.charAt(0)))) - proposals.add(new SCLCompletionProposal(value, offset - lastPart.length(), lastPart)); - } - for(TCon type : Environments.findTypesForPrefix(env, prefix)) { - proposals.add(new SCLCompletionProposal(type.name, type.module, SCLCompletionType.TYPE, offset - lastPart.length(), lastPart)); - } - - if(!prefix.contains(".")) { - for (ImportDeclaration decl : cachedImports) { - if (decl.localName != null && !decl.localName.isEmpty() && decl.localName.toLowerCase().startsWith(prefix.toLowerCase())) { - proposals.add(new SCLCompletionProposal(decl.localName, decl.moduleName, SCLCompletionType.CONST, offset - prefix.length(), prefix)); - } - } - } - Collections.sort(proposals, COMPARATOR); - moduleProposalCache = proposals; - proposalCache = moduleProposalCache.toArray(new SCLCompletionProposal[moduleProposalCache.size()]); - return proposalCache; - } - - private ArrayList processRelativeImports(List relativeImports) { - ArrayList absoluteImports = new ArrayList(relativeImports.size()); - for(ImportDeclaration relativeImport : relativeImports) { - if(relativeImport.moduleName.startsWith(".")) { - String absoluteModuleName = convertRelativeModulePath(relativeImport.moduleName); - if(absoluteModuleName != null) - absoluteImports.add(new ImportDeclaration( - absoluteModuleName, relativeImport.localName, - relativeImport.reexport, relativeImport.spec)); - } - else - absoluteImports.add(relativeImport); - } - return absoluteImports; - } - - private String convertRelativeModulePath(String relativeModuleName) { - String originalRelativeModuleName = relativeModuleName; - int p = moduleName.lastIndexOf('/'); - String parentPackage = p < 0 ? "" : moduleName.substring(0, p); - while(relativeModuleName.startsWith(".")) { - if(relativeModuleName.startsWith("./")) { - relativeModuleName = relativeModuleName.substring(2); - } - else if(relativeModuleName.startsWith("../")) { - relativeModuleName = relativeModuleName.substring(3); - if(parentPackage.isEmpty()) { - System.err.println("Couldn't resolve the relative module name " + originalRelativeModuleName + " when the current module name is " + moduleName + "."); - return null; - } - p = parentPackage.lastIndexOf('/'); - parentPackage = p < 0 ? "" : parentPackage.substring(0, p); - } - else { - System.err.println("Couldn't resolve the relative module name " + originalRelativeModuleName + ". It has an invalid syntax."); - return null; - } - } - return parentPackage + "/" + relativeModuleName; - } - - private static final Comparator COMPARATOR = new Comparator() { - - @Override - public int compare(SCLCompletionProposal prop1, SCLCompletionProposal prop2) { - if (prop1.isPrivate() && !prop2.isPrivate()) - return -1; - else if (!prop1.isPrivate() && prop2.isPrivate()) - return 1; - return prop1.getName().compareTo(prop2.getName()); - } - }; - - public SCLValue getValue(String text) { - try { - return Environments.getValue(env, text); - } catch (AmbiguousNameException e) { - // TODO could also return one of the conflicting alternatives - return null; - } - } - - public String getHoverInfo(String text) { - SCLValue value = getValue(text); - if (value != null) - return value.getDocumentation(); - else - return null; - } -} +package org.simantics.scl.ui.editor.completion; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.simantics.scl.compiler.common.names.Name; +import org.simantics.scl.compiler.compilation.EnvironmentOfModule; +import org.simantics.scl.compiler.elaboration.modules.SCLValue; +import org.simantics.scl.compiler.environment.AmbiguousNameException; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.environment.Environments; +import org.simantics.scl.compiler.errors.Failable; +import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException; +import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl; +import org.simantics.scl.compiler.module.ImportDeclaration; +import org.simantics.scl.compiler.module.InvalidModulePathException; +import org.simantics.scl.compiler.module.Module; +import org.simantics.scl.compiler.module.ModuleUtils; +import org.simantics.scl.compiler.module.repository.ImportFailureException; +import org.simantics.scl.compiler.types.TCon; +import org.simantics.scl.osgi.SCLOsgi; + +public class SCLTextEditorEnvironment { + + private String moduleName; + private SCLCompletionProposal[] proposalCache = new SCLCompletionProposal[0]; + private List moduleProposalCache = new ArrayList<>(0); + private Environment env; + + private List cachedImports = new ArrayList<>(); + private boolean cacheUpdated = false; + + public SCLTextEditorEnvironment(String moduleName) { + this.moduleName = moduleName; + } + + public void updateModuleName(String moduleName) { + this.moduleName = moduleName; + } + + public void updateEnvironment(IDocument document) { + String contents = document.get(); + String[] lines = contents.split("\\R+"); //$NON-NLS-1$ + List imports = new ArrayList<>(); + imports.add(new ImportDeclaration("StandardLibrary", "")); //$NON-NLS-1$ //$NON-NLS-2$ + for (String line : lines) { + line = line.trim(); + if (line.startsWith("import") || line.startsWith("include")) { //$NON-NLS-1$ //$NON-NLS-2$ + SCLParserImpl parser = new SCLParserImpl(new StringReader(line)); + try { + ImportDeclaration importDecl = (ImportDeclaration)parser.parseImport(); + imports.add(importDecl); + } catch (SCLSyntaxErrorException e) { + // Import cannot be handled, ignore + } + } + } + + imports = processRelativeImports(imports); + if (!imports.equals(cachedImports)) { + cachedImports = imports; + try { + env = SCLOsgi.MODULE_REPOSITORY.createEnvironment(cachedImports.toArray(new ImportDeclaration[cachedImports.size()]), null); + Failable module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName); + if(module.didSucceed()) + env = new EnvironmentOfModule(env, module.getResult()); + } catch (ImportFailureException e) { + //e.printStackTrace(); + } + } + } + + public ICompletionProposal[] getCompletionProposals(String prefix, int offset) { + int p = prefix.lastIndexOf('.'); + String lastPart = p==-1 ? prefix : prefix.substring(p+1); + + List proposals = new ArrayList<>(); + for(SCLValue value : Environments.findValuesForPrefix(env, prefix)) { + Name name = value.getName(); + if((name.module.equals(moduleName) || !value.isPrivate()) && !(name.name.contains("$") && Character.isLetter(name.name.charAt(0)))) //$NON-NLS-1$ + proposals.add(new SCLCompletionProposal(value, offset - lastPart.length(), lastPart)); + } + for(TCon type : Environments.findTypesForPrefix(env, prefix)) { + proposals.add(new SCLCompletionProposal(type.name, type.module, SCLCompletionType.TYPE, offset - lastPart.length(), lastPart)); + } + + if(!prefix.contains(".")) { //$NON-NLS-1$ + for (ImportDeclaration decl : cachedImports) { + if (decl.localName != null && !decl.localName.isEmpty() && decl.localName.toLowerCase().startsWith(prefix.toLowerCase())) { + proposals.add(new SCLCompletionProposal(decl.localName, decl.moduleName, SCLCompletionType.CONST, offset - prefix.length(), prefix)); + } + } + } + Collections.sort(proposals, COMPARATOR); + moduleProposalCache = proposals; + proposalCache = moduleProposalCache.toArray(new SCLCompletionProposal[moduleProposalCache.size()]); + return proposalCache; + } + + private ArrayList processRelativeImports(List relativeImports) { + ArrayList absoluteImports = new ArrayList(relativeImports.size()); + for(ImportDeclaration relativeImport : relativeImports) { + try { + String absoluteModuleName = ModuleUtils.resolveAbsolutePath(moduleName, relativeImport.moduleName); + absoluteImports.add(new ImportDeclaration( + relativeImport.location, + absoluteModuleName, relativeImport.localName, + relativeImport.reexport, relativeImport.spec)); + } catch (InvalidModulePathException e) { + // Nothing to do + } + } + return absoluteImports; + } + + private static final Comparator COMPARATOR = new Comparator() { + + @Override + public int compare(SCLCompletionProposal prop1, SCLCompletionProposal prop2) { + if (prop1.isPrivate() && !prop2.isPrivate()) + return -1; + else if (!prop1.isPrivate() && prop2.isPrivate()) + return 1; + return prop1.getName().compareTo(prop2.getName()); + } + }; + + public SCLValue getValue(String text) { + try { + return Environments.getValue(env, text); + } catch (AmbiguousNameException e) { + // TODO could also return one of the conflicting alternatives + return null; + } + } + + public String getHoverInfo(String text) { + SCLValue value = getValue(text); + if (value != null) + return value.getDocumentation(); + else + return null; + } +}