From 24e34ca27220c30ede538d3159be8d4246af7119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 14 Jun 2025 20:59:38 +0200 Subject: [PATCH] Added: AS3 - code completion (properties and methods) --- CHANGELOG.md | 1 + .../abc/avm2/parser/script/AbcIndexing.java | 62 +++- .../script/ActionScript3SimpleParser.java | 37 ++- .../script/ActionScript2SimpleParser.java | 9 +- .../flash/simpleparser/LinkHandler.java | 5 +- .../flash/simpleparser/Separator.java | 34 ++ .../flash/simpleparser/SimpleParser.java | 117 +++++-- .../decompiler/flash/gui/abc/ABCPanel.java | 5 + .../gui/editor/LineMarkedEditorPane.java | 7 + .../flash/gui/editor/VariableMarker.java | 297 +++++++++++++++++- .../flash/gui/locales/MainFrame.properties | 4 +- .../flash/gui/locales/MainFrame_cs.properties | 4 +- 12 files changed, 539 insertions(+), 43 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Separator.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 230393ca6..851c17147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ All notable changes to this project will be documented in this file. - [#1625] Error log frame - Save all to file button - [#2467] Show ImportAssets name/characterId in the title when there is only single one item - [#2468] Option for `-dumpas2` CLI command to use export names (`-exportNames` option) +- AS3 - code completion (properties and methods) ### Changed - AS1/2 - Single DoAction tag inside frame is now displayed directly as frame node diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java index 908aa44f8..a284c52ff 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java @@ -38,6 +38,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.helpers.Reference; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -566,7 +567,7 @@ public final class AbcIndexing { private Map> pkgToObjectsName = new LinkedHashMap<>(); private final Map classes = new HashMap<>(); - + private final Map instanceProperties = new HashMap<>(); private final Map classProperties = new HashMap<>(); @@ -614,6 +615,65 @@ public final class AbcIndexing { } return classNames; } + + public Set getClassTraitNames(GraphTargetItem cls, ABC abc, Integer scriptIndex, boolean getStatic, boolean getInstance, boolean getInheritance) { + ClassIndex ci = findClass(cls, abc, scriptIndex); + if (ci == null) { + return new LinkedHashSet<>(); + } + Set ret = new LinkedHashSet<>(); + getClassIndexTraitNames(ret, ci, getStatic, getInstance, getInheritance); + return ret; + } + + private void getClassIndexTraitNames(Set ret, ClassIndex ci, boolean getStatic, boolean getInstance, boolean getInheritance) { + GraphTargetItem ciName = multinameToType(ci.abc.instance_info.get(ci.index).name_index, ci.abc.constants); + + boolean isObject = ciName.equals(new TypeItem("Object")); + List ignoredObjectTraits = Arrays.asList("_init", "_dontEnumPrototype", "_setPropertyIsEnumerable"); + + if (getInstance) { + for (PropertyDef def : instanceProperties.keySet()) { + if (isObject && ignoredObjectTraits.contains(def.propName)) { + continue; + } + int nsKind = -1; + if (def.propNsIndex != 0) { + nsKind = def.abc.constants.getNamespace(def.propNsIndex).kind; + } + if (nsKind == Namespace.KIND_PRIVATE || nsKind == Namespace.KIND_PROTECTED || nsKind == Namespace.KIND_STATIC_PROTECTED) { + continue; + } + if (Objects.equals(def.parent, ciName)) { + ret.add(def.propName); + } + } + } + if (getStatic) { + for (PropertyDef def : classProperties.keySet()) { + if (isObject && ignoredObjectTraits.contains(def.propName)) { + continue; + } + int nsKind = -1; + if (def.propNsIndex != 0) { + nsKind = def.abc.constants.getNamespace(def.propNsIndex).kind; + } + if (nsKind == Namespace.KIND_PRIVATE || nsKind == Namespace.KIND_PROTECTED || nsKind == Namespace.KIND_STATIC_PROTECTED) { + continue; + } + if (Objects.equals(def.parent, ciName)) { + ret.add(def.propName); + } + } + } + + if (getInheritance && ci.parent != null) { + getClassIndexTraitNames(ret, ci.parent, getStatic, getInstance, getInheritance); + } + if (parent != null) { + parent.getClassIndexTraitNames(ret, ci, getStatic, getInstance, getInheritance); + } + } /** * Finds class in index. 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 3bb760143..bdf32025a 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 @@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.simpleparser.LinkHandler; import com.jpexs.decompiler.flash.simpleparser.MethodScope; import com.jpexs.decompiler.flash.simpleparser.Namespace; import com.jpexs.decompiler.flash.simpleparser.Path; +import com.jpexs.decompiler.flash.simpleparser.Separator; import com.jpexs.decompiler.flash.simpleparser.SimpleParseException; import com.jpexs.decompiler.flash.simpleparser.SimpleParser; import com.jpexs.decompiler.flash.simpleparser.TraitVarConstValueScope; @@ -46,6 +47,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Stack; /** @@ -168,8 +170,7 @@ public class ActionScript3SimpleParser implements SimpleParser { ret = true; break; case PARENT_OPEN: - call(errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); - lastVarName = lastVarName.add(Path.PATH_PARENTHESIS); + lastVarName = call(lastVarName, errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); ret = true; break; case DESCENDANTS: @@ -246,8 +247,10 @@ public class ActionScript3SimpleParser implements SimpleParser { while (s.isType(SymbolType.DOT, SymbolType.NULL_DOT, SymbolType.BRACKET_OPEN, SymbolType.TYPENAME)) { ParsedSymbol s2 = lex(); if (s.type == SymbolType.NULL_DOT) { + variables.add(new Separator(lastVarName, s.position)); lexer.pushback(s2); } else if (s.type == SymbolType.DOT) { + variables.add(new Separator(lastVarName, s.position)); if (s2.type == SymbolType.ATTRIBUTE) { //attribute } else { @@ -264,7 +267,10 @@ public class ActionScript3SimpleParser implements SimpleParser { } else if (s.type == SymbolType.BRACKET_OPEN) { lastVarName = lastVarName.add(Path.PATH_BRACKETS); expression(errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, true, variables, false, abc); - expectedType(errors, SymbolType.BRACKET_CLOSE); + s = lex(); + if (expected(errors, s, lexer.yyline(), SymbolType.BRACKET_CLOSE)) { + variables.add(new Separator(lastVarName, s.position)); + } ret = true; s = lex(); } else { @@ -331,6 +337,7 @@ public class ActionScript3SimpleParser implements SimpleParser { while (s.isType(SymbolType.DOT)) { variables.add(new Variable(false, fullName, identPos)); + variables.add(new Separator(fullName, s.position)); s = lex(); lastName = ""; if (s.type == SymbolType.ATTRIBUTE) { @@ -351,6 +358,7 @@ public class ActionScript3SimpleParser implements SimpleParser { } } else { if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.NAMESPACE, SymbolType.MULTIPLY)) { + lexer.pushback(s); return new Path(); } lastName = s.value.toString(); @@ -434,7 +442,7 @@ public class ActionScript3SimpleParser implements SimpleParser { return ret; } - private void call(List errors, TypeItem thisType, Reference needsActivation, List importedClasses, List openedNamespaces, HashMap registerVars, boolean inFunction, boolean inMethod, boolean isStatic, List variables, ABC abc) throws IOException, AVM2ParseException, SimpleParseException, InterruptedException { + private Path call(Path lastVarName, List errors, TypeItem thisType, Reference needsActivation, List importedClasses, List openedNamespaces, HashMap registerVars, boolean inFunction, boolean inMethod, boolean isStatic, List variables, ABC abc) throws IOException, AVM2ParseException, SimpleParseException, InterruptedException { //expected(SymbolType.PARENT_OPEN); //MUST BE HANDLED BY CALLER ParsedSymbol s = lex(); while (s.type != SymbolType.PARENT_CLOSE) { @@ -447,6 +455,12 @@ public class ActionScript3SimpleParser implements SimpleParser { break; } } + if (s.type == SymbolType.PARENT_CLOSE) { + lastVarName = lastVarName.add(Path.PATH_PARENTHESIS); + variables.add(new Separator(lastVarName, s.position)); + } + + return lastVarName; } private void method(List errors, boolean outsidePackage, boolean isPrivate, boolean isInterface, boolean isNative, String customAccess, Reference needsActivation, List importedClasses, boolean override, boolean isFinal, TypeItem thisType, List openedNamespaces, boolean isStatic, Path functionName, boolean isMethod, List variables, ABC abc, int methodNamePos, Reference returnTypeRef, Reference returnSubTypeRef) throws IOException, AVM2ParseException, SimpleParseException, InterruptedException { @@ -1369,7 +1383,8 @@ public class ActionScript3SimpleParser implements SimpleParser { case SUPER: //constructor call ParsedSymbol ss2 = lex(); if (ss2.type == SymbolType.PARENT_OPEN) { - call(errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); + Path lastVarName = new Path("super"); + lastVarName = call(lastVarName, errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); ret = true; } else { //no constructor call, but it could be calling parent methods... => handle in expression lexer.pushback(ss2); @@ -2062,7 +2077,7 @@ public class ActionScript3SimpleParser implements SimpleParser { applyType(errors, thisType, needsActivation, importedClasses, openedNamespaces, newvar, registerVars, inFunction, inMethod, isStatic, variables, abc); expectedType(errors, SymbolType.PARENT_CLOSE); expectedType(errors, SymbolType.PARENT_OPEN); - call(errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); + lastVarName = call(lastVarName, errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); ret = true; } else { @@ -2071,7 +2086,7 @@ public class ActionScript3SimpleParser implements SimpleParser { name(errors, thisType, needsActivation, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, importedClasses, abc); applyType(errors, thisType, needsActivation, importedClasses, openedNamespaces, newvar, registerVars, inFunction, inMethod, isStatic, variables, abc); expectedType(errors, SymbolType.PARENT_OPEN); - call(errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); + lastVarName = call(lastVarName, errors, thisType, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, abc); ret = true; } allowMemberOrCall = true; @@ -2280,7 +2295,11 @@ public class ActionScript3SimpleParser implements SimpleParser { Map> externalTypeIndexToReference, LinkHandler linkHandler, Map referenceToExternalTraitKey, - Map> externalTraitKeyToReference + Map> externalTraitKeyToReference, + Map separatorPosToType, + Map> localTypeTraitNames, + Map definitionToType, + Map definitionToCallType ) throws SimpleParseException, IOException, InterruptedException { List> allOpenedNamespaces = new ArrayList<>(); Reference sinitNeedsActivation = new Reference<>(false); @@ -2300,7 +2319,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); + SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, true, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, localTypeTraitNames, definitionToType, definitionToCallType); } /** 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 c2a88f6b9..6b552e354 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 @@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Set; /** * ActionScript 1/2 parser. @@ -1579,7 +1580,11 @@ public class ActionScript2SimpleParser implements SimpleParser { Map> externalTypeIndexToReference, LinkHandler linkHandler, Map referenceToExternalTraitKey, - Map> externalTraitKeyToReference + Map> externalTraitKeyToReference, + Map separatorPosToType, + Map> localTypeTraitNames, + Map definitionToType, + Map definitionToCallType ) throws SimpleParseException, IOException, InterruptedException { List vars = new ArrayList<>(); @@ -1670,7 +1675,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); + SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, false, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference, separatorPosToType, localTypeTraitNames, definitionToType, definitionToCallType); } private void versionRequired(List errors, ParsedSymbol s, int min) throws SimpleParseException { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkHandler.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkHandler.java index ef2cd315b..b8af5ad97 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkHandler.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkHandler.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.simpleparser; +import java.util.List; + /** * Handler of links. * @author JPEXS @@ -37,5 +39,6 @@ public interface LinkHandler { public void handleClassLink(Path className); public void handleTraitLink(Path className, String traitName); - + + public List getClassTraitNames(Path className, boolean getStatic, boolean getInstance, boolean getInheritance); } 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 new file mode 100644 index 000000000..9e9930c9c --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/Separator.java @@ -0,0 +1,34 @@ +/* + * 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 Separator implements VariableOrScope { + public Path parentName; + public int position; + + public Separator(Path parentName, int position) { + this.parentName = parentName; + this.position = 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 b2d618a96..5c99377c1 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 @@ -26,6 +26,7 @@ import java.util.Set; /** * Simple parser used for highlighting in editors. + * * @author JPEXS */ public interface SimpleParser { @@ -57,7 +58,11 @@ public interface SimpleParser { Map> externalTypeIndexToReference, LinkHandler linkHandler, Map referenceToExternalTraitKey, - Map> externalTraitKeyToReference + Map> externalTraitKeyToReference, + Map separatorPosToType, + Map> localTypeTraitNames, + Map definitionToType, + Map definitionToCallType ) throws SimpleParseException, IOException, InterruptedException; public static void parseVariablesList( @@ -72,17 +77,21 @@ public interface SimpleParser { Map> externalTypeIndexToReference, LinkHandler linkHandler, Map referenceToExternalTraitKey, - Map> externalTraitKeyToReference + Map> externalTraitKeyToReference, + Map separatorPosToType, + Map> localTypeTraitNames, + Map definitionToType, + Map definitionToCallType ) { List externalSimpleTypes = new ArrayList<>(); Map simpleExternalClassNameToFullClassName = new LinkedHashMap<>(); for (Path type : externalTypes) { externalSimpleTypes.add(type.getLast()); - simpleExternalClassNameToFullClassName.put(type.getLast(), type); + simpleExternalClassNameToFullClassName.put(type.getLast(), type); } - Map definitionToType = new LinkedHashMap<>(); - Map definitionToCallType = new LinkedHashMap<>(); + //Map definitionToType = new LinkedHashMap<>(); + //Map definitionToCallType = new LinkedHashMap<>(); Map definitionToSubType = new LinkedHashMap<>(); Map definitionToCallSubType = new LinkedHashMap<>(); Map traitFullNameToDefinition = new LinkedHashMap<>(); @@ -91,7 +100,16 @@ public interface SimpleParser { findClassTraits(privateVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); findClassTraits(sharedVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); - 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); + for (Path p : traitFullNameToDefinition.keySet()) { + Path cls = p.getParent(); + String traitName = p.getLast().toString(); + if (!localTypeTraitNames.containsKey(cls)) { + localTypeTraitNames.put(cls, new ArrayList<>()); + } + localTypeTraitNames.get(cls).add(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); for (Map.Entry entry : referenceToExternalTypeIndex.entrySet()) { if (!externalTypeIndexToReference.containsKey(entry.getValue())) { externalTypeIndexToReference.put(entry.getValue(), new ArrayList<>()); @@ -123,7 +141,8 @@ public interface SimpleParser { LinkHandler linkHandler, Map simpleExternalClassNameToFullClassName, Map referenceToExternalTraitKey, - Map> externalTraitKeyToReference + Map> externalTraitKeyToReference, + Map separatorPosToType ) { Map privateVarNameToDefinitionPosition = new LinkedHashMap<>(); privateVarNameToDefinitionPosition.putAll(parentVarNameToDefinitionPosition); @@ -132,6 +151,10 @@ public interface SimpleParser { privateVarFullNameToDefinitionPosition.putAll(parentVarFullNameToDefinitionPosition); for (VariableOrScope vt : privateVariables) { + if (vt instanceof Separator) { + Separator s = (Separator) vt; + searchTrait(s.parentName, s.position, true, separatorPosToType, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); + } if (vt instanceof Variable) { Variable v = (Variable) vt; if (v.definition) { @@ -156,7 +179,7 @@ public interface SimpleParser { } else if (externalSimpleTypes.contains(v.name)) { referenceToExternalTypeIndex.put(v.position, externalSimpleTypes.indexOf(v.name)); } else { - boolean traitFound = searchTrait(v, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); + boolean traitFound = searchTrait(v.name, v.position, false, separatorPosToType, 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); @@ -219,10 +242,14 @@ public interface SimpleParser { } } - 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); + 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); } } for (VariableOrScope vt : sharedVariables) { + if (vt instanceof Separator) { + Separator s = (Separator) vt; + searchTrait(s.parentName, s.position, true, separatorPosToType, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); + } if (vt instanceof Variable) { Variable v = (Variable) vt; if (v.definition) { @@ -249,7 +276,7 @@ public interface SimpleParser { } else if (externalSimpleTypes.contains(v.name)) { referenceToExternalTypeIndex.put(v.position, externalSimpleTypes.indexOf(v.name)); } else { - boolean traitFound = searchTrait(v, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); + boolean traitFound = searchTrait(v.name, v.position, false, separatorPosToType, 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); @@ -305,14 +332,14 @@ public interface SimpleParser { if (vName.toString().equals("this")) { subPrivateVarNameToDefinitionPosition.remove(new Path("this")); } - if (!innerFunctionCanUseTraits) { + if (!innerFunctionCanUseTraits) { subPrivateVarNameToDefinitionPosition.remove(vName.getLast()); } } } } - 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); + 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); } } } @@ -355,7 +382,10 @@ public interface SimpleParser { } public static boolean searchTrait( - Variable v, + Path vName, + int vPosition, + boolean separator, + Map separatorPosToType, Map privateVarFullNameToDefinitionPosition, Map privateVarNameToDefinitionPosition, Map definitionToType, @@ -371,12 +401,12 @@ public interface SimpleParser { Map> externalTraitKeyToReference ) { boolean traitFound = false; - if (v.hasParent()) { + if (vName.hasParent()) { //List parts = v.getParts(); - Path parts = v.name; - + Path parts = vName; + Integer definitionPos = null; - Path firstName = v.getFirstName(); + Path firstName = vName.getFirst(); if (privateVarFullNameToDefinitionPosition.containsKey(firstName)) { definitionPos = privateVarFullNameToDefinitionPosition.get(firstName); } else if (privateVarNameToDefinitionPosition.containsKey(firstName)) { @@ -427,12 +457,12 @@ public interface SimpleParser { break; } type = lastSubType.name; - } else { + } else { if (externalSubTypes.isEmpty()) { traitFound = false; break; } - type = externalSubTypes.remove(0); + type = externalSubTypes.remove(0); } } else { if (type == null) { @@ -444,9 +474,9 @@ public interface SimpleParser { type = simpleExternalClassNameToFullClassName.get(type); } traitKey = type.add(part); - Path newType = linkHandler.getTraitType(type, part.toString()); + Path newType = linkHandler.getTraitType(type, part.toString()); if (newType == null) { - traitFound = false; + traitFound = false; break; } externalSubTypes.clear(); @@ -477,7 +507,7 @@ public interface SimpleParser { } externalCallSubTypes.clear(); externalSubTypes.clear(); - externalCallType = null; + externalCallType = null; definitionPos = traitFullNameToDefinition.get(traitKey); type = definitionToType.get(definitionPos); lastSubType = null; @@ -486,16 +516,49 @@ public interface SimpleParser { if (traitFound) { if (definitionPos != null) { - definitionPosToReferences.get(definitionPos).add(v.position); - referenceToDefinition.put(v.position, definitionPos); + definitionPosToReferences.get(definitionPos).add(vPosition); + referenceToDefinition.put(vPosition, definitionPos); } else if (part != null) { if (!externalTraitKeyToReference.containsKey(traitKey)) { externalTraitKeyToReference.put(traitKey, new ArrayList<>()); } - externalTraitKeyToReference.get(traitKey).add(v.position); - referenceToExternalTraitKey.put(v.position, traitKey); + externalTraitKeyToReference.get(traitKey).add(vPosition); + referenceToExternalTraitKey.put(vPosition, traitKey); } - } + if (separator) { + separatorPosToType.put(vPosition, type); + } + } + } + } else if (separator) { + Integer definitionPos = null; + Path firstName = vName.getFirst(); + if (privateVarFullNameToDefinitionPosition.containsKey(firstName)) { + definitionPos = privateVarFullNameToDefinitionPosition.get(firstName); + } else if (privateVarNameToDefinitionPosition.containsKey(firstName)) { + definitionPos = privateVarNameToDefinitionPosition.get(firstName); + } + Path type = null; + if (definitionPos != null) { + if (definitionToType.containsKey(definitionPos)) { + type = definitionToType.get(definitionPos); + } + } else if (simpleExternalClassNameToFullClassName.containsKey(firstName)) { + type = simpleExternalClassNameToFullClassName.get(firstName); + } + if (type != null) { + if (definitionPos != null) { + definitionPosToReferences.get(definitionPos).add(vPosition); + referenceToDefinition.put(vPosition, definitionPos); + } + /* else { + if (!externalTraitKeyToReference.containsKey(traitKey)) { + externalTraitKeyToReference.put(traitKey, new ArrayList<>()); + } + externalTraitKeyToReference.get(traitKey).add(vPosition); + referenceToExternalTraitKey.put(vPosition, traitKey); + }*/ + separatorPosToType.put(vPosition, type); } } return traitFound; diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index f7ffa9ff1..6ee8a304d 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -1139,6 +1139,11 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener getClassTraitNames(Path className, boolean getStatic, boolean getInstance, boolean getInheritance) { + return new ArrayList<>(abc.getSwf().getAbcIndex().getClassTraitNames(new TypeItem(className.toString()), abc, decompiledTextArea.getScriptIndex(), getStatic, getInstance, getInheritance)); + } + }); decompiledTextArea.addScriptListener(new Runnable() { @Override diff --git a/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java b/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java index c0afe617b..28027163c 100644 --- a/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java @@ -30,8 +30,10 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.Rectangle2D; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.SortedSet; @@ -110,6 +112,11 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan public Path getTraitCallSubType(Path className, String traitName, int level) { return null; } + + @Override + public List getClassTraitNames(Path className, boolean getStatic, boolean getInstance, boolean getInheritance) { + return new ArrayList<>(); + } public static class LineMarker implements Comparable { diff --git a/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java b/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java index d7e3e9de6..e4120f69f 100644 --- a/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java +++ b/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.gui.ViewMessages; +import com.jpexs.decompiler.flash.simpleparser.LinkHandler; import com.jpexs.decompiler.flash.simpleparser.LinkType; import com.jpexs.decompiler.flash.simpleparser.Path; import com.jpexs.decompiler.flash.simpleparser.SimpleParseException; @@ -38,33 +39,43 @@ import java.awt.KeyboardFocusManager; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; +import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.Vector; +import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.BoxLayout; +import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JEditorPane; import javax.swing.JLabel; +import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JScrollBar; import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; @@ -113,9 +124,15 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC private Map simpleExternalClassNameToFullClassName = new LinkedHashMap<>(); private Map referenceToExternalTraitKey = new LinkedHashMap<>(); private Map> externalTraitKeyToReference = new LinkedHashMap<>(); + private Map separatorPosToType = new LinkedHashMap<>(); + private Map> localTypeTraitNames = new LinkedHashMap<>(); + private Map definitionToType = new LinkedHashMap<>(); + private Map definitionToCallType = new LinkedHashMap<>(); private MouseMotionAdapter mouseMotionAdapter; + private KeyAdapter keyAdapter; + private HighlightsPanel highlightsPanel; private ScrollPaneUI originalScrollPaneUI; @@ -146,15 +163,98 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC private boolean goingOut = false; + private JList codeCompletionList; + private DefaultListModel codeCompletionListModel; + private JPopupMenu codeCompletionPopup; + /** * Constructs a new Token highlighter */ public VariableMarker() { + codeCompletionListModel = new DefaultListModel<>(); + + codeCompletionList = new JList<>(); + codeCompletionList.setModel(codeCompletionListModel); + + codeCompletionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + codeCompletionList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + String selected = codeCompletionList.getSelectedValue(); + if (selected != null) { + completeCode(selected); + } + codeCompletionPopup.setVisible(false); + } + } + }); + + JScrollPane scroll = new JScrollPane(codeCompletionList); + codeCompletionPopup = new JPopupMenu(); + codeCompletionPopup.setLayout(new BorderLayout()); + codeCompletionPopup.add(scroll, BorderLayout.CENTER); + codeCompletionPopup.setPopupSize(200, 100); + + codeCompletionList.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + + String selected = codeCompletionList.getSelectedValue(); + if (selected != null) { + completeCode(selected); + } + codeCompletionPopup.setVisible(false); + if (selected == null) { + pane.dispatchEvent(e); + } + return; + } + if (e.getKeyCode() == KeyEvent.VK_DOWN + || e.getKeyCode() == KeyEvent.VK_UP + || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN + || e.getKeyCode() == KeyEvent.VK_PAGE_UP) { + return; + } + pane.dispatchEvent(e); + e.consume(); + } + + @Override + public void keyReleased(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_DOWN + || e.getKeyCode() == KeyEvent.VK_UP + || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN + || e.getKeyCode() == KeyEvent.VK_PAGE_UP) { + return; + } + pane.dispatchEvent(e); + e.consume(); + } + + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_DOWN + || e.getKeyCode() == KeyEvent.VK_UP + || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN + || e.getKeyCode() == KeyEvent.VK_PAGE_UP) { + return; + } + pane.dispatchEvent(e); + e.consume(); + } + }); + //list.setFocusable(false); } @Override public void caretUpdate(CaretEvent e) { markTokenAt(e.getDot()); + + if (codeCompletionPopup.isVisible()) { + showCodeCompletion(); + } } public void markTokenAt(int pos) { @@ -263,6 +363,12 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC void addMarkers(Token tok) { SyntaxDocument sDoc = (SyntaxDocument) pane.getDocument(); sDoc.readLock(); + + if (separatorPosToType.containsKey(tok.start)) { + sDoc.readUnlock(); + return; + } + int definitionPos = tok.start; if (referenceToDefinition.containsKey(tok.start)) { definitionPos = referenceToDefinition.get(tok.start); @@ -372,6 +478,146 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC } } + private void completeCode(String suggestion) { + try { + SyntaxDocument sDoc = (SyntaxDocument) pane.getDocument(); + sDoc.readLock(); + + int pos = pane.getCaretPosition(); + Token tokenAt = getNearestTokenAt(sDoc, pos); + + if (tokenAt != null && tokenAt.type == TokenType.IDENTIFIER) { + tokenAt = sDoc.getPrevToken(tokenAt); + } else if (tokenAt != null && tokenAt.start >= pos) { + tokenAt = sDoc.getPrevToken(tokenAt); + if (tokenAt != null && tokenAt.type == TokenType.IDENTIFIER) { + tokenAt = sDoc.getPrevToken(tokenAt); + } + } else if (tokenAt == null) { + while (tokenAt == null && pos >= 0) { + pos--; + tokenAt = getNearestTokenAt(sDoc, pos); + } + if (tokenAt == null) { + sDoc.readUnlock(); + return; + } + if (tokenAt.type == TokenType.IDENTIFIER) { + 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; + sDoc.readUnlock(); + pane.getDocument().remove(afterDot, pane.getCaretPosition() - afterDot); + pane.getDocument().insertString(afterDot, suggestion, null); + } catch (BadLocationException ex) { + //ignore + } + } + + private void showCodeCompletion() { + SyntaxDocument sDoc = (SyntaxDocument) pane.getDocument(); + sDoc.readLock(); + try { + 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) { + while (tokenAt == null && pos >= 0) { + pos--; + tokenAt = getNearestTokenAt(sDoc, pos); + } + if (tokenAt == null) { + return; + } + if (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; + } + + List suggestions = new ArrayList<>(); + if (separatorPosToType.containsKey(pos)) { + Path type = separatorPosToType.get(pos); + if (localTypeTraitNames.containsKey(type)) { + suggestions.addAll(localTypeTraitNames.get(type)); + suggestions.remove(type.getLast().toString()); //remove constructor + } else { + //type = externalTypes.get(referenceToExternalTypeIndex.get(pos)); + suggestions.addAll(((LineMarkedEditorPane) pane).getLinkHandler().getClassTraitNames(type, true, true, true)); + suggestions.remove(type.getLast().toString()); //remove constructor + } + } + if (suggestions.isEmpty()) { + codeCompletionPopup.setVisible(false); + return; + } + Collections.sort(suggestions); + if (!identText.isEmpty()) { + for (int i = suggestions.size() - 1; i >= 0; i--) { + String sug = suggestions.get(i); + if (!sug.startsWith(identText)) { + suggestions.remove(i); + } + } + } + + codeCompletionListModel.clear(); + codeCompletionListModel.addAll(suggestions); + + codeCompletionList.setSelectedIndex(-1); + + if (!codeCompletionPopup.isVisible() && !suggestions.isEmpty()) { + Rectangle2D caretCoords = View.textComponentModelToView(pane, pane.getCaretPosition()); + codeCompletionPopup.show(pane, (int) caretCoords.getX(), (int) (caretCoords.getY() + caretCoords.getHeight())); + pane.requestFocusInWindow(); + } + } catch (BadLocationException ex) { + //ignore + } finally { + sDoc.readUnlock(); + } + } + @Override public void install(JEditorPane editor) { this.pane = editor; @@ -407,8 +653,35 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC linkAdapter = new LinkAdapter(); + keyAdapter = new KeyAdapter() { + Timer tim = null; + + @Override + public void keyTyped(KeyEvent e) { + if (tim != null) { + tim.cancel(); + tim = null; + } + if (e.getKeyChar() == '.') { + tim = new Timer(); + tim.schedule(new TimerTask() { + @Override + public void run() { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + showCodeCompletion(); + } + }); + } + }, 100); + } + } + }; + pane.addMouseListener(linkAdapter); pane.addMouseMotionListener(linkAdapter); + pane.addKeyListener(keyAdapter); //No standard AddKeyListener as we want to catch Ctrl globally no matter of focus kevEventPostProcessor = new KeyEventPostProcessor() { @@ -438,6 +711,14 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC } }, "find-declaration", AppStrings.translate("abc.action.find-declaration"), "control B"); + View.addEditorAction(pane, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + showCodeCompletion(); + } + + }, "code-completion", AppStrings.translate("action.code-completion"), "control SPACE"); + documentUpdated(); markTokenAt(editor.getCaretPosition()); status = Status.INSTALLING; @@ -612,12 +893,14 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC errorsTimer = null; } View.removeEditorAction(pane, "find-declaration"); + View.removeEditorAction(pane, "code-completion"); pane.removePropertyChangeListener(this); pane.getDocument().removeDocumentListener(this); pane.removeCaretListener(this); pane.removeMouseMotionListener(mouseMotionAdapter); pane.removeMouseMotionListener(linkAdapter); pane.removeMouseListener(linkAdapter); + pane.removeKeyListener(keyAdapter); KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(kevEventPostProcessor); mouseMotionAdapter = null; /*if (editor instanceof LineMarkedEditorPane) { @@ -675,6 +958,10 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC Map> newExternalTypeIndexToReference = new LinkedHashMap<>(); Map newReferenceToExternalTraitKey = new LinkedHashMap<>(); Map> newExternalTraitKeyToReference = new LinkedHashMap<>(); + Map newSeparatorPosToType = new LinkedHashMap<>(); + Map> newLocalTypeTraitNames = new LinkedHashMap<>(); + Map newDefinitionToType = new LinkedHashMap<>(); + Map newDefinitionToCallType = new LinkedHashMap<>(); parser.parse( fullText, newDefinitionPosToReferences, @@ -684,7 +971,11 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC newReferenceToExternalTypeIndex, newExternalTypeIndexToReference, ((LineMarkedEditorPane) pane).getLinkHandler(), - newReferenceToExternalTraitKey, newExternalTraitKeyToReference + newReferenceToExternalTraitKey, newExternalTraitKeyToReference, + newSeparatorPosToType, + newLocalTypeTraitNames, + newDefinitionToType, + newDefinitionToCallType ); Map newSimpleExternalClassNameToFullClassName = new LinkedHashMap<>(); @@ -700,6 +991,10 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC simpleExternalClassNameToFullClassName = newSimpleExternalClassNameToFullClassName; referenceToExternalTraitKey = newReferenceToExternalTraitKey; externalTraitKeyToReference = newExternalTraitKeyToReference; + separatorPosToType = newSeparatorPosToType; + localTypeTraitNames = newLocalTypeTraitNames; + definitionToType = newDefinitionToType; + definitionToCallType = newDefinitionToCallType; for (SimpleParseException ex : newErrors) { errors.put((int) ex.position, ex.getMessage()); } diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index c82549a04..ff63340ad 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1075,4 +1075,6 @@ message.link.reallyGo = Do you really want to go to another SWF? contextmenu.exportSubspriteAnimation = Export subsprite animation -contextmenu.showInFlashPlayer = Show in the Flash Player \ No newline at end of file +contextmenu.showInFlashPlayer = Show in the Flash Player + +action.code-completion = Code completion \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 883a0d915..fa99d214a 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1074,4 +1074,6 @@ message.link.reallyGo = Opravdu chcete p\u0159ej\u00edt do jin\u00e9ho SWF? contextmenu.exportSubspriteAnimation = Export animace podsprit\u016f -contextmenu.showInFlashPlayer = Zobrazit ve Flash Playeru \ No newline at end of file +contextmenu.showInFlashPlayer = Zobrazit ve Flash Playeru + +action.code-completion = Dokon\u010dov\u00e1n\u00ed k\u00f3du \ No newline at end of file