intellism / vscode-comment-translate

vscode 注释翻译插件, 不干扰正常代码,方便快速阅读源码。
https://marketplace.visualstudio.com/items?itemName=intellsmi.comment-translate
MIT License
493 stars 78 forks source link

[FR] Support for AutoHotKey #194

Closed boromyr closed 2 weeks ago

boromyr commented 11 months ago

Would it be possible to add support for AutoHotKey files?

intellism commented 11 months ago

Please provide an example of an AutoHotKey file and the vscode highlighting plugin used.

boromyr commented 11 months ago

Example AutoHotKey script, a normal Json library:

class JSON
{
    class parse extends JSON.functor
    {
        call(self, ByRef param_string, param_reviver:="")
        {
            this.rev := isObject(param_reviver) ? param_reviver : false
            ; Object keys(and array indices) are temporarily stored in arrays so that
            ; we can enumerate them in the order they appear in the string instead
            ; of alphabetically. Skip if no reviver function is specified.
            this.keys := this.rev ? {} : false

            static quot := chr(34), bashq := "\" quot
                , json_value := quot "{[01234567890-tfn"
                , json_value_or_array_closing := quot "{[]01234567890-tfn"
                , object_key_or_object_closing := quot "}"

            key := ""
            is_key := false
            root := {}
            stack := [root]
            next := json_value
            pos := 0

            while ((ch := subStr(param_string, ++pos, 1)) != "") {
                if inStr(" `t`r`n", ch) {
                    continue
                }
                if !inStr(next, ch, 1) {
                    this.parseError(next, param_string, pos)
                }

                holder := stack[1]
                is_array := holder.IsArray

                if inStr(",:", ch) {
                    next := (is_key := !is_array && ch == ",") ? quot : json_value

                } else if (inStr("}]", ch)) {
                    objRemoveAt(stack, 1)
                    next := stack[1]==root ? "" : stack[1].IsArray ? ",]" : ",}"

                } else {
                    if (inStr("{[", ch)) {
                        ; Check if Array() is overridden and if its return value has
                        ; the 'IsArray' property. If so, Array() will be called normally,
                        ; otherwise, use a custom base object for arrays
                        static json_array := func("Array").isBuiltIn || ![].IsArray ? {IsArray: true} : 0

                        ; sacrifice readability for minor(actually negligible) performance gain
                        (ch == "{")
                            ? ( is_key := true
                              , value := {}
                              , next := object_key_or_object_closing )
                            ; ch == "["
                            : ( value := json_array ? new json_array : []
                              , next := json_value_or_array_closing )

                        ObjInsertAt(stack, 1, value)

                        if (this.keys) {
                            this.keys[value] := []
                        }
                    } else {
                        if (ch == quot) {
                            i := pos
                            while (i := inStr(param_string, quot,, i+1)) {
                                value := strReplace(subStr(param_string, pos+1, i-pos-1), "\\", "\u005c")

                                static tail := A_AhkVersion<"2" ? 0 : -1
                                if (subStr(value, tail) != "\") {
                                    break
                                }
                            }

                            if (!i) {
                                this.parseError("'", param_string, pos)
                            }

                            value := strReplace(value, "\/",  "/")
                            , value := strReplace(value, bashq, quot)
                            , value := strReplace(value, "\b", "`b")
                            , value := strReplace(value, "\f", "`f")
                            , value := strReplace(value, "\n", "`n")
                            , value := strReplace(value, "\r", "`r")
                            , value := strReplace(value, "\t", "`t")

                            pos := i ; update pos

                            i := 0
                            while (i := inStr(value, "\",, i+1)) {
                                if (!(subStr(value, i+1, 1) == "u")) {
                                    this.parseError("\", param_string, pos - strLen(subStr(value, i+1)))
                                }

                                uffff := Abs("0x" subStr(value, i+2, 4))
                                if (A_IsUnicode || uffff < 0x100) {
                                    value := subStr(value, 1, i-1) chr(uffff) subStr(value, i+6)
                                }
                            }

                            if (is_key) {
                                key := value, next := ":"
                                continue
                            }

                        } else {
                            value := subStr(param_string, pos, i := regExMatch(param_string, "[\]\},\s]|$",, pos)-pos)

                            if value is number
                            {
                                if value is integer
                                {
                                    value += 0
                                }
                            }
                            else if (value == "true" || value == "false") {
                                value := %value% + 0
                            } else if (value == "null") {
                                value := ""
                            } else {
                                ; we can do more here to pinpoint the actual culprit
                                ; but that's just too much extra work.
                                this.parseError(next, text, pos, i)
                            }
                            pos += i - 1
                        }
                        next := holder == root ? "" : is_array ? ",]" : ",}"
                    } ; If inStr("{[", ch) { ... } else

                    is_array? key := objPush(holder, value) : holder[key] := value

                    if (this.keys && this.keys.hasKey(holder)) {
                        this.keys[holder].Push(key)
                    }
                }
            } ; while ( ... )
            return this.rev ? this.walk(root, "") : root[""]
        }

        parseError(param_expect, ByRef param_string, pos, param_length:=1)
        {
            static quot := chr(34), qurly := quot "}"

            line := strSplit(subStr(param_string, 1, pos), "`n", "`r").length()
            col := pos - inStr(param_string, "`n",, -(strLen(param_string)-pos+1))
            msg := format("{1}`n`nLine:`t{2}`nCol:`t{3}`nChar:`t{4}"
                , (param_expect == "")     ?    "Extra data"
                : (param_expect == "'")    ?    "Unterminated string starting at"
                : (param_expect == "\")    ?    "Invalid \escape"
                : (param_expect == ":")    ?    "Expecting ':' delimiter"
                : (param_expect == quot)   ?    "Expecting object key enclosed in double quotes"
                : (param_expect == qurly)  ?    "Expecting object key enclosed in double quotes or object closing '}'"
                : (param_expect == ",}")   ?    "Expecting ',' delimiter or object closing '}'"
                : (param_expect == ",]")   ?    "Expecting ',' delimiter or array closing ']'"
                : inStr(param_expect, "]") ?    "Expecting JSON value or array closing ']'"
                :                               "Expecting JSON value(string, number, true, false, null, object or array)"
            , line, col, pos)

            static offset := A_AhkVersion < "2" ? -3 : -4
            throw Exception(msg, offset, subStr(param_string, pos, param_length))
        }

        walk(param_holder, param_key)
        {
            value := param_holder[param_key]
            if (isObject(value)) {
                for i, k in this.keys[value] {
                    ; check if objhasKey(value, k) ??
                    v := this.walk(value, k)
                    if (v != JSON.Undefined) {
                        value[k] := v
                    } else {
                        objDelete(value, k)
                    }
                }
            }
            return this.rev.call(param_holder, param_key, value)
        }
    }

    class stringify extends JSON.functor
    {
        call(self, param_value, param_replacer:="", space:="")
        {
            this.rep := isObject(param_replacer) ? param_replacer : ""

            this.gap := ""
            if (space) {
                if space is integer
                {
                    loop, % ((n := Abs(space))>10 ? 10 : n) {
                        this.gap .= " "
                    }
                } else {
                    this.gap := subStr(space, 1, 10)
                }
                this.indent := "`n"
            }
            return this.str({"": param_value}, "")
        }

        str(param_holder, param_key)
        {
            param_value := param_holder[param_key]

            if (this.rep) {
                param_value := this.rep.call(param_holder, param_key, objhasKey(param_holder, param_key) ? param_value : JSON.Undefined)
            }

            if isObject(param_value) {
                ; Check object type, skip serialization for other object types such as
                ; ComObject, Func, BoundFunc, FileObject, RegExMatchObject, Property, etc.
                static type := A_AhkVersion<"2" ? "" : func("Type")
                if (type ? type.call(param_value) == "Object" : objGetCapacity(param_value) != "") {
                    if (this.gap) {
                        stepback := this.indent
                        this.indent .= this.gap
                    }

                    is_array := param_value.IsArray
                    ; Array() is not overridden, rollback to old method of
                    ; identifying array-like objects. Due to the use of a for-loop
                    ; sparse arrays such as '[1,,3]' are detected as objects({}).
                    if (!is_array) {
                        for i in param_value {
                            is_array := i == A_Index
                        }
                        until (!is_array)
                    }

                    str := ""
                    if (is_array) {
                        loop, % param_value.length() {
                            if (this.gap) {
                                str .= this.indent
                            }
                            v := this.str(param_value, A_Index)
                            str .= (v != "") ? v "," : "null,"
                        }
                    } else {
                        colon := this.gap ? ": " : ":"
                        for k in param_value {
                            v := this.str(param_value, k)
                            if (v != "") {
                                if (this.gap) {
                                    str .= this.indent
                                }
                                str .= this.quote(k) colon v ","
                            }
                        }
                    }

                    if (str != "") {
                        str := rTrim(str, ",")
                        if (this.gap) {
                            str .= stepback
                        }
                    }

                    if (this.gap) {
                        this.indent := stepback
                    }
                    return is_array ? "[" str "]" : "{" str "}"
                }
            } else {
                ; is_number ? param_value : "param_value"
                return objGetCapacity([param_value], 1) == "" ? param_value : this.quote(param_value)
            }
        }

        quote(param_string)
        {
            static quot := chr(34), bashq := "\" quot

            if (param_string != "") {
                param_string := strReplace(param_string,  "\", "\\")
                ; , param_string := strReplace(param_string,  "/",  "\/") ; optional in ECMAScript
                , param_string := strReplace(param_string, quot, bashq)
                , param_string := strReplace(param_string, "`b", "\b")
                , param_string := strReplace(param_string, "`f", "\f")
                , param_string := strReplace(param_string, "`n", "\n")
                , param_string := strReplace(param_string, "`r", "\r")
                , param_string := strReplace(param_string, "`t", "\t")

                static rx_escapable := A_AhkVersion<"2" ? "O)[^\x20-\x7e]" : "[^\x20-\x7e]"
                while regExMatch(param_string, rx_escapable, m) {
                    param_string := strReplace(param_string, m.Value, format("\u{1:04x}", ord(m.Value)))
                }
            }
            return quot param_string quot
        }
    }

    class test extends JSON.functor
    {
        call(self, param_string:="")
        {
            if (isObject(param_string) || param_string == "") {
                return false
            }

            try {
                JSON.parse(param_string)
            } catch error {
                return false
            }
            return true
        }
    }

    ; For use with reviver and replacer functions since AutoHotkey does not
    ; have an 'undefined' type. Returning blank("") or 0 won't work since these
    ; can't be distnguished from actual JSON values. This leaves us with objects.
    ; Replacer() - the caller may return a non-serializable AHK objects such as
    ; ComObject, Func, BoundFunc, FileObject, RegExMatchObject, and Property to
    ; mimic the behavior of returning 'undefined' in JavaScript but for the sake
    ; of code readability and convenience, it's better to do 'return JSON.Undefined'.
    ; Internally, the property returns a ComObject with the variant type of VT_EMPTY.
    Undefined[]
    {
        get {
            static empty := {}, vt_empty := ComObject(0, &empty, 1)
            return vt_empty
        }
    }

    class functor
    {
        __call(param_method, ByRef param_args, param_extargs*)
        {
            ; When casting to call(), use a new instance of the "function object"
            ; so as to avoid directly storing the properties(used across sub-methods)
            ; into the "function object" itself.
            if isObject(param_method) {
                return (new this).call(param_method, param_args, param_extargs*)
            } else if (param_method == "") {
                return (new this).call(param_args, param_extargs*)
            }
        }
    }
}

the extension for the syntax is https://marketplace.visualstudio.com/items?itemName=mark-wiemer.vscode-autohotkey-plus-plus

intellism commented 2 weeks ago

If textmate syntax highlighting extension is installed, supported by default