diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java index b251e5c26..4a29aef92 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java @@ -469,8 +469,9 @@ public class ActionScript3SimpleParser implements SimpleParser { private void function(List errors, boolean isInterface, boolean isNative, Reference needsActivation, List importedClasses, TypeItem thisType, List openedNamespaces, Path functionName, boolean isMethod, List variables, ABC abc, int functionNamePos, boolean isStatic, Reference returnTypeRef, Reference returnSubTypeRef) throws IOException, AVM2ParseException, SimpleParseException, InterruptedException { - ParsedSymbol s; - expectedType(errors, SymbolType.PARENT_OPEN); + ParsedSymbol s = lex(); + expected(errors, s, lexer.yyline(), SymbolType.PARENT_OPEN); + int scopePos = s.position; s = lex(); List paramNames = new ArrayList<>(); List paramPositions = new ArrayList<>(); @@ -543,21 +544,26 @@ public class ActionScript3SimpleParser implements SimpleParser { subvariables.add(new Variable(true, paramNames.get(paramNames.size() - 1), paramPositions.get(paramNames.size() - 1), null, new Path("Array"), null)); } Reference needsActivation2 = new Reference<>(false); + if (!isInterface && !isNative) { s = lex(); expected(errors, s, lexer.yyline(), SymbolType.CURLY_OPEN); subvariables.add(new Variable(true, new Path("arguments"), -s.position - 1, null, new Path("Array"), null)); commands(errors, thisType, needsActivation2, importedClasses, openedNamespaces, new Stack<>(), new HashMap<>(), new HashMap<>(), true, isMethod, isStatic, 0, subvariables, abc); - expectedType(errors, SymbolType.CURLY_CLOSE); + s = lex(); + expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE); } else { - expectedType(errors, SymbolType.SEMICOLON); + s = lex(); + expected(errors, s, lexer.yyline(), SymbolType.SEMICOLON); } + int scopeEndPos = s.position; if (isMethod) { - MethodScope ms = new MethodScope(subvariables, isStatic); + + MethodScope ms = new MethodScope(scopePos, scopeEndPos, subvariables, isStatic); variables.add(ms); } else { - FunctionScope fs = new FunctionScope(subvariables, isStatic); + FunctionScope fs = new FunctionScope(scopePos, scopeEndPos, subvariables, isStatic); variables.add(fs); } } @@ -861,8 +867,9 @@ public class ActionScript3SimpleParser implements SimpleParser { if (s.type == SymbolType.ASSIGN) { List constVarVariables = new ArrayList<>(); expression(errors, thisType, new Reference<>(false), importedClasses, openedNamespaces, new HashMap<>(), false, false, isStatic, true, constVarVariables, false, abc); - classVariables.add(new TraitVarConstValueScope(constVarVariables, isStatic)); + int scopePos = s.position; s = lex(); + classVariables.add(new TraitVarConstValueScope(scopePos, s.position, constVarVariables, isStatic)); } if (s.type != SymbolType.SEMICOLON) { lexer.pushback(s); @@ -1031,6 +1038,7 @@ public class ActionScript3SimpleParser implements SimpleParser { switch (s.type) { case CLASS: case INTERFACE: + int scopePos = s.position; isEmpty = false; List subOpenedNamespaces = new ArrayList<>(openedNamespaces); boolean isInterface = false; @@ -1084,9 +1092,10 @@ public class ActionScript3SimpleParser implements SimpleParser { classTraits(errors, !inPackage, cinitNeedsActivation, importedClasses, subOpenedNamespaces, pkgName, subNameStr, isInterface, iinitNeedsActivation, abc, classVariables); - sinitVariables.add(new ClassScope(classVariables)); + s = lex(); + sinitVariables.add(new ClassScope(scopePos, s.position, classVariables)); - expectedType(errors, SymbolType.CURLY_CLOSE); + expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE); break; case FUNCTION: isEmpty = false; @@ -1557,6 +1566,7 @@ public class ActionScript3SimpleParser implements SimpleParser { s = lex(); boolean found = false; while (s.type == SymbolType.CATCH) { + int scopePos = s.position; expectedType(errors, SymbolType.PARENT_OPEN); s = lex(); if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.THIS, SymbolType.SUPER, SymbolType.STRING_OP)) { @@ -1571,8 +1581,10 @@ public class ActionScript3SimpleParser implements SimpleParser { List catchVars = new ArrayList<>(); expectedType(errors, SymbolType.CURLY_OPEN); commands(errors, thisType, needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, isStatic, forinlevel, catchVars, abc); - expectedType(errors, SymbolType.CURLY_CLOSE); - variables.add(new CatchScope(new Variable(true, enamestr, ePos, null, catchType, null, catchSubType.getVal(), null), catchVars)); + int eScopePos = s.position; + s = lex(); + expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE); + variables.add(new CatchScope(eScopePos, s.position, new Variable(true, enamestr, ePos, null, catchType, null, catchSubType.getVal(), null), catchVars)); s = lex(); found = true; } @@ -2300,7 +2312,9 @@ public class ActionScript3SimpleParser implements SimpleParser { Map separatorIsStatic, Map> localTypeTraitNames, Map definitionToType, - Map definitionToCallType + Map definitionToCallType, + Integer caretPosition, + List variableSuggestions ) throws SimpleParseException, IOException, InterruptedException { List> allOpenedNamespaces = new ArrayList<>(); Reference sinitNeedsActivation = new Reference<>(false); @@ -2320,7 +2334,7 @@ public class ActionScript3SimpleParser implements SimpleParser { //Logger.getLogger(ActionScript3SimpleParser.class.getName()).log(Level.SEVERE, null, ex); throw new SimpleParseException(str, ex.line); } - SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, true, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType); + SimpleParser.parseVariablesList(vars, definitionPosToReferences, referenceToDefinition, errors, true, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType, caretPosition, variableSuggestions); } /** diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java index 0e0d6a8f7..e7071e0bf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java @@ -164,12 +164,14 @@ public class ActionScript2SimpleParser implements SimpleParser { } private FunctionScope function(List errors, boolean withBody, Path functionName, int functionNamePosition, boolean isMethod, List variables, boolean inTellTarget, Reference hasEval, boolean isStatic) throws IOException, InterruptedException, SimpleParseException, ActionParseException { - ParsedSymbol s; - expectedType(errors, SymbolType.PARENT_OPEN); + ParsedSymbol s = lex(); + int scopePos = s.position; + expected(errors, s, lexer.yyline(), SymbolType.PARENT_OPEN); s = lex(); List paramNames = new ArrayList<>(); List paramPositions = new ArrayList<>(); + int scopeEndPos; while (s.type != SymbolType.PARENT_CLOSE) { if (s.type != SymbolType.COMMA) { lexer.pushback(s); @@ -191,6 +193,7 @@ public class ActionScript2SimpleParser implements SimpleParser { } } } + scopeEndPos = s.position; List subvariables = new ArrayList<>(); Reference subHasEval = new Reference<>(false); @@ -205,7 +208,9 @@ public class ActionScript2SimpleParser implements SimpleParser { if (withBody) { expectedType(errors, SymbolType.CURLY_OPEN); commands(errors, true, isMethod, 0, inTellTarget, subvariables, subHasEval); - expectedType(errors, SymbolType.CURLY_CLOSE); + s = lex(); + expected(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE); + scopeEndPos = s.position; } if (subHasEval.getVal()) { @@ -213,9 +218,9 @@ public class ActionScript2SimpleParser implements SimpleParser { } if (isMethod) { - return new MethodScope(subvariables, isStatic); + return new MethodScope(scopePos, scopeEndPos, subvariables, isStatic); } - return new FunctionScope(subvariables, isStatic); + return new FunctionScope(scopePos, scopeEndPos, subvariables, isStatic); } private boolean traits(List errors, boolean isInterface, Path className, List variables, boolean inTellTarget, Reference hasEval) throws IOException, InterruptedException, SimpleParseException, ActionParseException { @@ -276,10 +281,12 @@ public class ActionScript2SimpleParser implements SimpleParser { s = lex(); } if (s.type == SymbolType.ASSIGN) { + int scopePos = s.position; List subVariables = new ArrayList<>(); expression(errors, false, false, false, true, subVariables, false, hasEval); - variables.add(new TraitVarConstValueScope(subVariables, isStatic)); s = lex(); + variables.add(new TraitVarConstValueScope(scopePos, s.position, subVariables, isStatic)); + } if (s.type != SymbolType.SEMICOLON) { lexer.pushback(s); @@ -783,6 +790,7 @@ public class ActionScript2SimpleParser implements SimpleParser { ret = true; break; case CLASS: + int scopePos = s.position; Path className = type(errors, true, variables); if (className != null) { s = lex(); @@ -800,10 +808,12 @@ public class ActionScript2SimpleParser implements SimpleParser { variables.add(new Variable(true, new Path("this"), s.position)); List subVariables = new ArrayList<>(); traits(errors, false, className, subVariables, inTellTarget, hasEval); - ClassScope cs = new ClassScope(subVariables); + + s = lex(); + ClassScope cs = new ClassScope(scopePos, s.position, subVariables); variables.add(cs); - expectedType(errors, SymbolType.CURLY_CLOSE); + expectedType(errors, s, lexer.yyline(), SymbolType.CURLY_CLOSE); ret = true; } break; @@ -993,6 +1003,7 @@ public class ActionScript2SimpleParser implements SimpleParser { s = lex(); boolean found = false; while (s.type == SymbolType.CATCH) { + int catchScopePos = s.position; expectedType(errors, SymbolType.PARENT_OPEN); ParsedSymbol si = lex(); if (expectedIdentifier(errors, si, lexer.yyline(), SymbolType.STRING)) { @@ -1007,8 +1018,9 @@ public class ActionScript2SimpleParser implements SimpleParser { List subvariables = new ArrayList<>(); command(errors, inFunction, inMethod, forinlevel, inTellTarget, subvariables, hasEval); - - variables.add(new CatchScope(new Variable(true, new Path((String) si.value), si.position), subvariables)); + s = lex(); + variables.add(new CatchScope(catchScopePos, s.position, new Variable(true, new Path((String) si.value), si.position), subvariables)); + lexer.pushback(s); } s = lex(); found = true; @@ -1585,7 +1597,9 @@ public class ActionScript2SimpleParser implements SimpleParser { Map separatorIsStatic, Map> localTypeTraitNames, Map definitionToType, - Map definitionToCallType + Map definitionToCallType, + Integer caretPosition, + List variableSuggestions ) throws SimpleParseException, IOException, InterruptedException { List vars = new ArrayList<>(); @@ -1676,7 +1690,7 @@ public class ActionScript2SimpleParser implements SimpleParser { } catch (ActionParseException ex) { errors.add(new SimpleParseException(ex.getMessage(), ex.line, ex.position)); } - SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, false, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType); + SimpleParser.parseVariablesList(vars, definitionPosToReferences, referenceToDefinition, errors, false, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, localTypeTraitNames, definitionToType, definitionToCallType, caretPosition, variableSuggestions); } private void versionRequired(List errors, ParsedSymbol s, int min) throws SimpleParseException { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/CatchScope.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/CatchScope.java index 76c01d836..8bb4f329b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/CatchScope.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/CatchScope.java @@ -27,11 +27,15 @@ public class CatchScope implements Scope { private final List privateItems; private final List sharedItems; + private final int position; + private final int endPosition; - public CatchScope(Variable catchVariable, List catchBody) { + public CatchScope(int position, int endPosition, Variable catchVariable, List catchBody) { this.privateItems = new ArrayList<>(); this.privateItems.add(catchVariable); this.sharedItems = catchBody; + this.position = position; + this.endPosition = endPosition; } @Override @@ -44,4 +48,14 @@ public class CatchScope implements Scope { return privateItems; } + @Override + public int getPosition() { + return position; + } + + @Override + public int getEndPosition() { + return endPosition; + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/ClassScope.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/ClassScope.java index b60f3ac4e..481490183 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/ClassScope.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/ClassScope.java @@ -26,9 +26,13 @@ import java.util.List; public class ClassScope implements Scope { private final List privateItems; + private final int position; + private final int endPosition; - public ClassScope(List traits) { + public ClassScope(int position, int endPosition, List traits) { this.privateItems = traits; + this.position = position; + this.endPosition = endPosition; } @Override @@ -40,4 +44,14 @@ public class ClassScope implements Scope { public List getPrivateItems() { return privateItems; } + + @Override + public int getPosition() { + return position; + } + + @Override + public int getEndPosition() { + return endPosition; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/FunctionScope.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/FunctionScope.java index d1083dbae..3a242dedc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/FunctionScope.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/FunctionScope.java @@ -27,10 +27,14 @@ public class FunctionScope implements Scope { private final List privateItems; private final boolean isStatic; + private final int position; + private final int endPosition; - public FunctionScope(List functionBody, boolean isStatic) { + public FunctionScope(int position, int endPosition, List functionBody, boolean isStatic) { this.privateItems = functionBody; this.isStatic = isStatic; + this.position = position; + this.endPosition = endPosition; } public boolean isStatic() { @@ -46,4 +50,15 @@ public class FunctionScope implements Scope { public List getPrivateItems() { return privateItems; } + + @Override + public int getPosition() { + return position; + } + + @Override + public int getEndPosition() { + return endPosition; + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/MethodScope.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/MethodScope.java index 7c8ad7190..e67ba8bb6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/MethodScope.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/MethodScope.java @@ -24,8 +24,8 @@ import java.util.List; */ public class MethodScope extends FunctionScope { - public MethodScope(List functionBody, boolean isStatic) { - super(functionBody, isStatic); + public MethodScope(int position, int endPosition, List functionBody, boolean isStatic) { + super(position, endPosition, functionBody, isStatic); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Scope.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Scope.java index 8424d10e9..187f6c415 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Scope.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Scope.java @@ -27,4 +27,6 @@ public interface Scope extends VariableOrScope { public List getSharedItems(); public List getPrivateItems(); + + public int getEndPosition(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Separator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Separator.java index 9e9930c9c..917d9ca12 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Separator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Separator.java @@ -29,6 +29,9 @@ public class Separator implements VariableOrScope { this.position = position; } - + @Override + public int getPosition() { + return position; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java index 926029a99..dd2f1ca42 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java @@ -18,8 +18,10 @@ package com.jpexs.decompiler.flash.simpleparser; import java.io.IOException; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -63,11 +65,12 @@ public interface SimpleParser { Map separatorIsStatic, Map> localTypeTraitNames, Map definitionToType, - Map definitionToCallType + Map definitionToCallType, + Integer caretPosition, + List variableSuggestions ) throws SimpleParseException, IOException, InterruptedException; public static void parseVariablesList( - List privateVariables, List sharedVariables, Map> definitionPosToReferences, Map referenceToDefinition, @@ -81,9 +84,11 @@ public interface SimpleParser { Map> externalTraitKeyToReference, Map separatorPosToType, Map separatorIsStatic, - Map> localTypeTraitNames, + Map> localTypeTraitNames, Map definitionToType, - Map definitionToCallType + Map definitionToCallType, + Integer caretPosition, + List variableSuggestions ) { List externalSimpleTypes = new ArrayList<>(); Map simpleExternalClassNameToFullClassName = new LinkedHashMap<>(); @@ -98,9 +103,17 @@ public interface SimpleParser { Map definitionToCallSubType = new LinkedHashMap<>(); Map traitFullNameToDefinition = new LinkedHashMap<>(); + List variables = new ArrayList<>(); + for (VariableOrScope vs : sharedVariables) { + variables.add(new VariableOrScopeWithAccess(vs, true)); + } + Map positionToStatic = new LinkedHashMap<>(); - findClassTraits(privateVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); - findClassTraits(sharedVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); + + Map parentVarFullNameToDefinitionPosition = new LinkedHashMap<>(); + Map parentVarNameToDefinitionPosition = new LinkedHashMap<>(); + + findClassTraits(variables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, parentVarFullNameToDefinitionPosition, parentVarNameToDefinitionPosition); for (Path p : traitFullNameToDefinition.keySet()) { int definition = traitFullNameToDefinition.get(p); @@ -116,18 +129,35 @@ public interface SimpleParser { localTypeTraitNames.get(cls).add((isStatic ? "static::" : "") + traitName); } - parseVariablesList(privateVariables, sharedVariables, definitionPosToReferences, referenceToDefinition, new LinkedHashMap<>(), new LinkedHashMap<>(), positionToStatic, true, errors, null, innerFunctionCanUseTraits, externalSimpleTypes, externalTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic); + parseVariablesList(variables, definitionPosToReferences, referenceToDefinition, parentVarFullNameToDefinitionPosition, parentVarNameToDefinitionPosition, positionToStatic, true, errors, null, innerFunctionCanUseTraits, externalSimpleTypes, externalTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, caretPosition, variableSuggestions, null, null); for (Map.Entry entry : referenceToExternalTypeIndex.entrySet()) { if (!externalTypeIndexToReference.containsKey(entry.getValue())) { externalTypeIndexToReference.put(entry.getValue(), new ArrayList<>()); } externalTypeIndexToReference.get(entry.getValue()).add(entry.getKey()); } + + if (caretPosition != null && variableSuggestions.isEmpty()) { + if ((variables.isEmpty() || variables.get(variables.size() - 1).var.getPosition() <= caretPosition)) { + for (Path p : parentVarNameToDefinitionPosition.keySet()) { + if (parentVarNameToDefinitionPosition.get(p) >= 0) { + variableSuggestions.add(p.getFirst().toString()); + } + } + variableSuggestions.add("--finish--"); + } + } + + if (!variableSuggestions.isEmpty()) { + variableSuggestions.remove(variableSuggestions.size() - 1); + } + Set uniqueSuggestions = new LinkedHashSet<>(variableSuggestions); + variableSuggestions.clear(); + variableSuggestions.addAll(uniqueSuggestions); } public static void parseVariablesList( - List privateVariables, - List sharedVariables, + List variables, Map> definitionPosToReferences, Map referenceToDefinition, Map parentVarFullNameToDefinitionPosition, @@ -150,7 +180,11 @@ public interface SimpleParser { Map referenceToExternalTraitKey, Map> externalTraitKeyToReference, Map separatorPosToType, - Map separatorIsStatic + Map separatorIsStatic, + Integer caretPosition, + List variableSuggestions, + Integer scopeStartPos, + Integer scopeEndPos ) { Map privateVarNameToDefinitionPosition = new LinkedHashMap<>(); privateVarNameToDefinitionPosition.putAll(parentVarNameToDefinitionPosition); @@ -158,7 +192,30 @@ public interface SimpleParser { Map privateVarFullNameToDefinitionPosition = new LinkedHashMap<>(); privateVarFullNameToDefinitionPosition.putAll(parentVarFullNameToDefinitionPosition); - for (VariableOrScope vt : privateVariables) { + for (int i = 0; i < variables.size(); i++) { + VariableOrScopeWithAccess vsa = variables.get(i); + VariableOrScope vt = variables.get(i).var; + VariableOrScope vt2 = i + 1 < variables.size() ? variables.get(i + 1).var : null; + + if (i == 0 + && scopeStartPos != null + && caretPosition != null + && caretPosition >= scopeStartPos + && vt.getPosition() > caretPosition + && variableSuggestions.isEmpty()) { + for (Path p : parentVarNameToDefinitionPosition.keySet()) { + if (parentVarNameToDefinitionPosition.get(p) >= 0) { + variableSuggestions.add(p.getFirst().toString()); + } + } + for (Path p : privateVarNameToDefinitionPosition.keySet()) { + if (privateVarNameToDefinitionPosition.get(p) >= 0) { + variableSuggestions.add(p.getFirst().toString()); + } + } + variableSuggestions.add("--finish--"); + } + if (vt instanceof Separator) { Separator s = (Separator) vt; searchTrait(s.parentName, s.position, true, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); @@ -166,6 +223,11 @@ public interface SimpleParser { if (vt instanceof Variable) { Variable v = (Variable) vt; if (v.definition) { + + if (vsa.shared) { + parentVarFullNameToDefinitionPosition.put(v.name, v.position); + parentVarNameToDefinitionPosition.put(v.getLastName(), v.position); + } privateVarFullNameToDefinitionPosition.put(v.name, v.position); privateVarNameToDefinitionPosition.put(v.getLastName(), v.position); if (!definitionPosToReferences.containsKey(v.position)) { @@ -189,8 +251,10 @@ public interface SimpleParser { } else { boolean traitFound = searchTrait(v.name, v.position, false, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); if (!traitFound) { - parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1); - parentVarNameToDefinitionPosition.put(v.getLastName(), -v.position - 1); + if (vsa.shared) { + parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1); + parentVarNameToDefinitionPosition.put(v.getLastName(), -v.position - 1); + } privateVarFullNameToDefinitionPosition.put(v.name, -v.position - 1); privateVarNameToDefinitionPosition.put(v.getLastName(), -v.position - 1); definitionPosToReferences.put(-v.position - 1, new ArrayList<>()); @@ -200,103 +264,6 @@ public interface SimpleParser { } } else { - if ("this".equals(v.name.toString()) && isStatic) { - errors.add(new SimpleParseException("Cannot use this in static context", -1, v.position)); - } else { - int definitionPos; - if (privateVarFullNameToDefinitionPosition.containsKey(v.name)) { - definitionPos = privateVarFullNameToDefinitionPosition.get(v.name); - } else { - definitionPos = privateVarNameToDefinitionPosition.get(v.name); - } - boolean staticDefinition = definitionPos >= 0 ? positionToStatic.get(definitionPos) : true; - if (!(!staticDefinition && isStatic)) { - definitionPosToReferences.get(definitionPos).add(v.position); - referenceToDefinition.put(v.position, definitionPos); - } else { - //errors.add(new SimpleParseException("Cannot reference instance variable from static context", -1, v.position)); - } - } - } - } - } - if (vt instanceof Scope) { - Scope vs = (Scope) vt; - boolean subStatic = isStatic; - if (vs instanceof FunctionScope) { - subStatic = ((FunctionScope) vs).isStatic(); - } - if (vs instanceof TraitVarConstValueScope) { - subStatic = ((TraitVarConstValueScope) vs).isStatic(); - } - - //if its inner function (not a method), remove all this variables - Map subPrivateVarFullNameToDefinitionPosition = privateVarFullNameToDefinitionPosition; - Map subPrivateVarNameToDefinitionPosition = privateVarNameToDefinitionPosition; - if ((vs instanceof FunctionScope) && (!(vs instanceof MethodScope))) { - subPrivateVarFullNameToDefinitionPosition = new LinkedHashMap<>(subPrivateVarFullNameToDefinitionPosition); - subPrivateVarNameToDefinitionPosition = new LinkedHashMap<>(subPrivateVarNameToDefinitionPosition); - Set keys = new HashSet<>(subPrivateVarFullNameToDefinitionPosition.keySet()); - for (Path vName : keys) { - if (vName.toString().equals("this") || vName.getFirst().toString().equals("this")) { - subPrivateVarFullNameToDefinitionPosition.remove(vName); - if (vName.toString().equals("this")) { - subPrivateVarNameToDefinitionPosition.remove(new Path("this")); - } - if (!innerFunctionCanUseTraits) { - subPrivateVarNameToDefinitionPosition.remove(vName.getLast()); - } - } - } - } - - parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, subPrivateVarFullNameToDefinitionPosition, subPrivateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, externalFullTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic); - } - } - for (VariableOrScope vt : sharedVariables) { - if (vt instanceof Separator) { - Separator s = (Separator) vt; - searchTrait(s.parentName, s.position, true, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); - } - if (vt instanceof Variable) { - Variable v = (Variable) vt; - if (v.definition) { - parentVarFullNameToDefinitionPosition.put(v.name, v.position); - parentVarNameToDefinitionPosition.put(v.getLastName(), v.position); - privateVarFullNameToDefinitionPosition.put(v.name, v.position); - privateVarNameToDefinitionPosition.put(v.getLastName(), v.position); - if (!definitionPosToReferences.containsKey(v.position)) { - definitionPosToReferences.put(v.position, new ArrayList<>()); - } - positionToStatic.put(v.position, v.isStatic != null ? v.isStatic : isStatic); - if (v.type != null) { - definitionToType.put(v.position, v.type); - } - if (v.subType != null) { - definitionToSubType.put(v.position, v.subType); - } - } else { - if (!privateVarFullNameToDefinitionPosition.containsKey(v.name) - && !privateVarNameToDefinitionPosition.containsKey(v.name)) { - - if (externalFullTypes.contains(v.name)) { - referenceToExternalTypeIndex.put(v.position, externalFullTypes.indexOf(v.name)); - } else if (externalSimpleTypes.contains(v.name)) { - referenceToExternalTypeIndex.put(v.position, externalSimpleTypes.indexOf(v.name)); - } else { - boolean traitFound = searchTrait(v.name, v.position, false, separatorPosToType, separatorIsStatic, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); - if (!traitFound) { - parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1); - parentVarNameToDefinitionPosition.put(v.getFirstName(), -v.position - 1); - privateVarFullNameToDefinitionPosition.put(v.name, -v.position - 1); - privateVarNameToDefinitionPosition.put(v.getFirstName(), -v.position - 1); - definitionPosToReferences.put(-v.position - 1, new ArrayList<>()); - definitionPosToReferences.get(-v.position - 1).add(v.position); - referenceToDefinition.put(v.position, -v.position - 1); - } - } - } else { - if ("this".equals(v.name) && isStatic) { errors.add(new SimpleParseException("Cannot use this in static context", -1, v.position)); } else { @@ -317,6 +284,7 @@ public interface SimpleParser { } } } + if (vt instanceof Scope) { Scope vs = (Scope) vt; boolean subStatic = isStatic; @@ -347,22 +315,72 @@ public interface SimpleParser { } } - parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, externalFullTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic); + List list = new ArrayList<>(); + for (VariableOrScope it : vs.getPrivateItems()) { + list.add(new VariableOrScopeWithAccess(it, false)); + } + for (VariableOrScope it : vs.getSharedItems()) { + list.add(new VariableOrScopeWithAccess(it, true)); + } + list.sort(new Comparator() { + @Override + public int compare(VariableOrScopeWithAccess o1, VariableOrScopeWithAccess o2) { + return o1.var.getPosition() - o2.var.getPosition(); + } + }); + parseVariablesList(list, definitionPosToReferences, referenceToDefinition, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, externalFullTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, separatorIsStatic, caretPosition, variableSuggestions, vs.getPosition(), vs.getEndPosition()); + } + + if (vt2 != null && caretPosition != null && variableSuggestions.isEmpty()) { + if (vt.getPosition() <= caretPosition && vt2.getPosition() > caretPosition) { + if (vt instanceof Variable) { + for (Path p : parentVarNameToDefinitionPosition.keySet()) { + if (parentVarNameToDefinitionPosition.get(p) >= 0) { + variableSuggestions.add(p.getFirst().toString()); + } + } + for (Path p : privateVarNameToDefinitionPosition.keySet()) { + if (privateVarNameToDefinitionPosition.get(p) >= 0) { + variableSuggestions.add(p.getFirst().toString()); + } + } + variableSuggestions.add("--finish--"); + } + } + } + } + + if (caretPosition != null && variableSuggestions.isEmpty() && scopeEndPos != null) { + if (scopeEndPos > caretPosition) { + for (Path p : parentVarNameToDefinitionPosition.keySet()) { + if (parentVarNameToDefinitionPosition.get(p) >= 0) { + variableSuggestions.add(p.getFirst().toString()); + } + } + for (Path p : privateVarNameToDefinitionPosition.keySet()) { + if (privateVarNameToDefinitionPosition.get(p) >= 0) { + variableSuggestions.add(p.getFirst().toString()); + } + } + variableSuggestions.add("--finish--"); } } } public static void findClassTraits( - List variables, + List variables, Map traitFullNameToDefinition, Map> definitionPosToReferences, Map positionToStatic, Map definitionToType, Map definitionToCallType, Map definitionToSubType, - Map definitionToCallSubType + Map definitionToCallSubType, + Map parentVarFullNameToDefinitionPosition, + Map parentVarNameToDefinitionPosition ) { - for (VariableOrScope v : variables) { + for (VariableOrScopeWithAccess vsa : variables) { + VariableOrScope v = vsa.var; if (v instanceof Type) { Type t = (Type) v; if (t.definition) { @@ -386,11 +404,20 @@ public interface SimpleParser { definitionToCallSubType.put(ct.position, ct.callSubType); } traitFullNameToDefinition.put(ct.getFullIdentifier(), ((ClassTrait) v).position); + + parentVarFullNameToDefinitionPosition.put(ct.name, ct.position); + parentVarNameToDefinitionPosition.put(ct.getLastName(), ct.position); } if (v instanceof Scope) { Scope s = (Scope) v; - findClassTraits(s.getPrivateItems(), traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); - findClassTraits(s.getSharedItems(), traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); + List list = new ArrayList<>(); + for (VariableOrScope it : s.getPrivateItems()) { + list.add(new VariableOrScopeWithAccess(it, false)); + } + for (VariableOrScope it : s.getSharedItems()) { + list.add(new VariableOrScopeWithAccess(it, true)); + } + findClassTraits(list, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, parentVarFullNameToDefinitionPosition, parentVarNameToDefinitionPosition); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/TraitVarConstValueScope.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/TraitVarConstValueScope.java index 02a6eb0c9..3f021acec 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/TraitVarConstValueScope.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/TraitVarConstValueScope.java @@ -25,10 +25,15 @@ import java.util.List; */ public class TraitVarConstValueScope implements Scope { + private final int position; + private final int endPosition; + private List sharedItems; private final boolean isStatic; - public TraitVarConstValueScope(List sharedItems, boolean isStatic) { + public TraitVarConstValueScope(int position, int endPosition, List sharedItems, boolean isStatic) { + this.position = position; + this.endPosition = endPosition; this.sharedItems = sharedItems; this.isStatic = isStatic; } @@ -46,4 +51,16 @@ public class TraitVarConstValueScope implements Scope { public List getPrivateItems() { return new ArrayList<>(); } + + @Override + public int getPosition() { + return position; + } + + @Override + public int getEndPosition() { + return endPosition; + } + + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Variable.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Variable.java index 43b2d445c..d4407178c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Variable.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Variable.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.simpleparser; -import java.util.Arrays; import java.util.List; /** @@ -81,4 +80,9 @@ public class Variable implements VariableOrScope { public boolean hasParent() { return name.hasParent(); } + + @Override + public int getPosition() { + return position; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/VariableOrScope.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/VariableOrScope.java index d90185d19..75ea0a140 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/VariableOrScope.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/VariableOrScope.java @@ -21,5 +21,5 @@ package com.jpexs.decompiler.flash.simpleparser; * @author JPEXS */ public interface VariableOrScope { - + public int getPosition(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/VariableOrScopeWithAccess.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/VariableOrScopeWithAccess.java new file mode 100644 index 000000000..95447adf9 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/VariableOrScopeWithAccess.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2025 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.simpleparser; + +/** + * + * @author JPEXS + */ +public class VariableOrScopeWithAccess { + public VariableOrScope var; + public boolean shared; + + public VariableOrScopeWithAccess(VariableOrScope var, boolean shared) { + this.var = var; + this.shared = shared; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java b/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java index 060df41fd..ab329b027 100644 --- a/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java +++ b/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java @@ -93,6 +93,7 @@ import jsyntaxpane.actions.ActionUtils; import jsyntaxpane.components.Markers; import jsyntaxpane.components.SyntaxComponent; import jsyntaxpane.util.Configuration; +import natorder.NaturalOrderComparator; import org.pushingpixels.substance.internal.ui.SubstanceScrollBarUI; /** @@ -129,6 +130,7 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC private Map definitionToType = new LinkedHashMap<>(); private Map definitionToCallType = new LinkedHashMap<>(); private Map separatorIsStatic = new LinkedHashMap<>(); + private List variableSuggestions = new ArrayList<>(); private MouseMotionAdapter mouseMotionAdapter; @@ -377,6 +379,9 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC if (referenceToExternalTypeIndex.containsKey(tok.start)) { int typeIndex = referenceToExternalTypeIndex.get(tok.start); for (int i : externalTypeIndexToReference.get(typeIndex)) { + if (separatorPosToType.containsKey(i)) { + continue; + } Token referenceToken = getIdentifierTokenAt(sDoc, i); if (referenceToken != null) { Markers.SimpleMarker markerKind = marker; @@ -399,6 +404,9 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC if (referenceToExternalTraitKey.containsKey(tok.start)) { Path traitKey = referenceToExternalTraitKey.get(tok.start); for (int i : externalTraitKeyToReference.get(traitKey)) { + if (separatorPosToType.containsKey(i)) { + continue; + } Token referenceToken = getIdentifierTokenAt(sDoc, i); if (referenceToken != null) { Markers.SimpleMarker markerKind = marker; @@ -437,6 +445,9 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC } occurencesPositions.add(definitionToken.start); for (int i : definitionPosToReferences.get(definitionPos)) { + if (separatorPosToType.containsKey(i)) { + continue; + } Token referenceToken = getIdentifierTokenAt(sDoc, i); if (referenceToken != null) { markerKind = marker; @@ -487,11 +498,14 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC int pos = pane.getCaretPosition(); Token tokenAt = getNearestTokenAt(sDoc, pos); + String identText = ""; if (tokenAt != null && tokenAt.type == TokenType.IDENTIFIER) { + identText = sDoc.getText(tokenAt.start, pos - tokenAt.start); tokenAt = sDoc.getPrevToken(tokenAt); } else if (tokenAt != null && tokenAt.start >= pos) { tokenAt = sDoc.getPrevToken(tokenAt); if (tokenAt != null && tokenAt.type == TokenType.IDENTIFIER) { + identText = sDoc.getText(tokenAt.start, pos - tokenAt.start); tokenAt = sDoc.getPrevToken(tokenAt); } } else if (tokenAt == null) { @@ -499,28 +513,22 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC pos--; tokenAt = getNearestTokenAt(sDoc, pos); } - if (tokenAt == null) { - sDoc.readUnlock(); - return; - } - if (tokenAt.type == TokenType.IDENTIFIER) { + if (tokenAt != null && tokenAt.type == TokenType.IDENTIFIER) { + identText = sDoc.getText(tokenAt.start, pos - tokenAt.start); tokenAt = sDoc.getPrevToken(tokenAt); } } - if (tokenAt == null) { - sDoc.readUnlock(); - return; - } - - boolean isDot = tokenAt.type == TokenType.OPERATOR ? ".".equals(sDoc.getText(tokenAt.start, tokenAt.length)) : false; - if (!isDot) { - sDoc.readUnlock(); - return; - } - int afterDot = tokenAt.start + 1; + + boolean isDot = tokenAt != null && tokenAt.type == TokenType.OPERATOR ? ".".equals(sDoc.getText(tokenAt.start, tokenAt.length)) : false; sDoc.readUnlock(); - pane.getDocument().remove(afterDot, pane.getCaretPosition() - afterDot); - pane.getDocument().insertString(afterDot, suggestion, null); + if (isDot) { + int afterDot = tokenAt.start + 1; + pane.getDocument().remove(afterDot, pane.getCaretPosition() - afterDot); + pane.getDocument().insertString(afterDot, suggestion, null); + } else { + pane.getDocument().remove(pane.getCaretPosition() - identText.length(), identText.length()); + pane.getDocument().insertString(pane.getCaretPosition(), suggestion, null); + } } catch (BadLocationException ex) { //ignore } @@ -548,74 +556,67 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC pos--; tokenAt = getNearestTokenAt(sDoc, pos); } - if (tokenAt == null) { - return; - } - if (tokenAt.type == TokenType.IDENTIFIER) { + if (tokenAt != null && tokenAt.type == TokenType.IDENTIFIER) { identText = sDoc.getText(tokenAt.start, pos - tokenAt.start); tokenAt = sDoc.getPrevToken(tokenAt); } } - if (tokenAt == null) { - codeCompletionPopup.setVisible(false); - return; - } - - boolean isDot = tokenAt.type == TokenType.OPERATOR ? ".".equals(sDoc.getText(tokenAt.start, tokenAt.length)) : false; - if (!isDot) { - codeCompletionPopup.setVisible(false); - return; - } - - Token prevToken = sDoc.getPrevToken(tokenAt); - boolean isCall = prevToken.pairValue == -1; //-1 = -PARENT - - pos = tokenAt.start; - - if (!separatorPosToType.containsKey(pos)) { - return; - } - + + boolean isDot = tokenAt != null && tokenAt.type == TokenType.OPERATOR ? ".".equals(sDoc.getText(tokenAt.start, tokenAt.length)) : false; List suggestions = new ArrayList<>(); - if (separatorPosToType.containsKey(pos)) { - Path type = separatorPosToType.get(pos); + if (isDot) { - boolean isStatic = false; - if (separatorIsStatic.containsKey(pos) && separatorIsStatic.get(pos)) { - isStatic = true; - } + Token prevToken = sDoc.getPrevToken(tokenAt); + boolean isCall = prevToken.pairValue == -1; //-1 = -PARENT - if (localTypeTraitNames.containsKey(type)) { - for (String traitName : localTypeTraitNames.get(type)) { - if (isStatic && !traitName.startsWith("static::")) { - continue; - } - if (traitName.startsWith("static::")) { - traitName = traitName.substring("static::".length()); - } - suggestions.add(traitName); - } - suggestions.remove(type.getLast().toString()); //remove constructor - } else { - //type = externalTypes.get(referenceToExternalTypeIndex.get(pos)); - List traitNames = ((LineMarkedEditorPane) pane).getLinkHandler().getClassTraitNames(type, true, true, true); - for (String traitName : traitNames) { - if (isStatic && !traitName.startsWith("static::")) { - continue; - } - if (traitName.startsWith("static::")) { - traitName = traitName.substring("static::".length()); - } - suggestions.add(traitName); - } - suggestions.remove(type.getLast().toString()); //remove constructor + pos = tokenAt.start; + + if (!separatorPosToType.containsKey(pos)) { + return; } + + if (separatorPosToType.containsKey(pos)) { + Path type = separatorPosToType.get(pos); + + boolean isStatic = false; + if (separatorIsStatic.containsKey(pos) && separatorIsStatic.get(pos)) { + isStatic = true; + } + + if (localTypeTraitNames.containsKey(type)) { + for (String traitName : localTypeTraitNames.get(type)) { + if (isStatic && !traitName.startsWith("static::")) { + continue; + } + if (traitName.startsWith("static::")) { + traitName = traitName.substring("static::".length()); + } + suggestions.add(traitName); + } + suggestions.remove(type.getLast().toString()); //remove constructor + } else { + //type = externalTypes.get(referenceToExternalTypeIndex.get(pos)); + List traitNames = ((LineMarkedEditorPane) pane).getLinkHandler().getClassTraitNames(type, true, true, true); + for (String traitName : traitNames) { + if (isStatic && !traitName.startsWith("static::")) { + continue; + } + if (traitName.startsWith("static::")) { + traitName = traitName.substring("static::".length()); + } + suggestions.add(traitName); + } + suggestions.remove(type.getLast().toString()); //remove constructor + } + } + } else { + suggestions.addAll(variableSuggestions); } if (suggestions.isEmpty()) { codeCompletionPopup.setVisible(false); return; } - Collections.sort(suggestions); + Collections.sort(suggestions, new NaturalOrderComparator()); if (!identText.isEmpty()) { for (int i = suggestions.size() - 1; i >= 0; i--) { String sug = suggestions.get(i); @@ -624,7 +625,7 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC } } } - + codeCompletionListModel.clear(); codeCompletionListModel.addAll(suggestions); @@ -687,6 +688,9 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC tim = null; } if (e.getKeyChar() == '.') { + if (!editor.isEditable()) { + return; + } tim = new Timer(); tim.schedule(new TimerTask() { @Override @@ -738,6 +742,10 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC View.addEditorAction(pane, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { + if (!pane.isEditable()) { + return; + } + documentUpdated(); showCodeCompletion(); } @@ -987,6 +995,7 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC Map newDefinitionToType = new LinkedHashMap<>(); Map newDefinitionToCallType = new LinkedHashMap<>(); Map newSeparatorIsStatic = new LinkedHashMap<>(); + List newVariableSuggestions = new ArrayList<>(); parser.parse( fullText, newDefinitionPosToReferences, @@ -1001,7 +1010,9 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC newSeparatorIsStatic, newLocalTypeTraitNames, newDefinitionToType, - newDefinitionToCallType + newDefinitionToCallType, + pane.getCaretPosition(), + newVariableSuggestions ); Map newSimpleExternalClassNameToFullClassName = new LinkedHashMap<>(); @@ -1022,6 +1033,7 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC definitionToType = newDefinitionToType; definitionToCallType = newDefinitionToCallType; separatorIsStatic = newSeparatorIsStatic; + variableSuggestions = newVariableSuggestions; for (SimpleParseException ex : newErrors) { errors.put((int) ex.position, ex.getMessage()); } @@ -1067,6 +1079,9 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC } private LinkType getLinkType(Token token) { + if (separatorPosToType.containsKey(token.start)) { + return LinkType.NO_LINK; + } if (definitionPosToReferences.containsKey(token.start)) { return LinkType.NO_LINK; }