Search code examples
actionscript-3flashace-editor

Simple autocomplete with Ace Editor in AS3?


I'm working in XML and I'd like to provide autocomplete suggestions for the attributes for specific node types using AS3.

For example, if the user is has a cursor in the following node:

 <s:Button label="Hello World"/>

I'd like autocomplete to show "width, height, x, y".

I'm trying to get the node name and namespace and then give the editor a list of attributes that should appear in autocomplete.

I found similar questions but those are using a service call and a few that are out dated. I may delete this question if it is a duplicate.

Ace Editor for AS3 here.


Solution

  • In my case, for AS3, it is a combination of items:

    ace.setCompleters(null); // I'm removing existing autocomplete  
    ace.addCompleter(codeCompleter); // adding my own
    
    public var autoCompleteErrorMessage:String = "Nothing available";
    public function codeCompleter(editor:Object, session:Object, position:Object, prefix:String, callback:Function):void {
        var row:int = position.row;
        var column:int = position.column;
    
        /*
        if (prefix.length === 0) { 
            callback(null, []);
            return;
        }
        */
        //var myList:Array = {value: "message", caption: "Caption to user", meta: "Type shown", score: "I don't know"};
    
        var testing:Boolean = false;
    
        if (testing) {
            callback(autoCompleteErrorMessage, [{value:"addedToStage"},{value:"added"},{value:"adding"}]);
        }
        else {
            callback(autoCompleteErrorMessage, attributes);
        }
    }
    
    
    protected function cursorChangeHandler(event:Event):void {
    
        var qname:QName = getQNameFromCursorPosition(ace.row, ace.column);
        if (qname==null) {
            if (attributes.length) {
                attributes = [];
            }
            return;
        }
    
        if (qname) { 
            attributes = getSuggestionListFromObject(classObject);
            autoCompleteErrorMessage = null;
            lastSelectedQName = qname;
        }
    }
    
    
    public static var XML_TAG_NAME:String       = "meta.tag.tag-name.xml";
    public static var XML_TAG_OPEN:String       = "meta.tag.punctuation.tag-open.xml";
    public static var XML_TAG_CLOSE:String      = "meta.tag.punctuation.tag-close.xml";
    public static var XML_ATTRIBUTE_NAME:String = "entity.other.attribute-name.xml";
    
    public function getQNameFromCursorPosition(row:int, column:int):QName {
        var token:Object;
        var line:String;
        var type:String;
        var value:String;
        var found:Boolean;
        var qname:QName;
    
        for (; row > -1; row--) {
            line = ace.getLine(row);
            column = line.length;
    
            for (; column>-1; column--) {
                token = ace.getTokenAt(row, column);
                type = token ? token.type : "";
    
                if (type==XML_TAG_NAME) {
                    value = token.value;
                    found = true;
                }
            }
    
            if (found) break;
        }
    
        if (found) {
            qname = new QName("", value);
        }
    
        return qname;
    }
    

    The getQNameFromCursorPosition() method is fragile and I'm looking into a new method using the jumpToMatching() method.