'''
Sample config file for bim3
'''
import os

# Quirks work the same as they did in bim2, except for the obvious syntax change
quirk('TERM','screen','no24bit','noitalic')
quirk('TERM','xterm-256color','caninsert','canpaste','cansgrmouse')
quirk('TERMINAL_EMULATOR','JetBrains','nobce')

# checkprop() returns 0 if we _can_ do something, so
# call it with 'not' to check capabilities...
if not checkprop('can_unicode'):
    tabindicator('»')
    spaceindicator('·')

# Themes are actually Kuroko functions now, but we load
# them into a table like always for the :theme command
theme('sunsmoke')

# Non-string values are coerced into strings, so these commands
# can take integer values.
global.git(1)
global.statusbar(1)
global.autohidetabs(1)
smartcomplete(1)

def enable_kuroko():
    import syntax.c
    let krk_types = [
        'KrkObj','KrkValue',
        'KrkClass','KrkString','KrkInstance','krk_integer_type',
        'KrkList','KrkDict','KrkTuple','KrkClosure','KrkBoundMethod',
        'KrkCodeObject','KrkToken','KrkChunk','KrkNative',
        # Compiler stuff
        'Local','Upvalue','FunctionType','ParseRule',
        'Compiler','ClassCompiler','Parser',
    ]
    syntax.c.CHighlighter.types.extend(krk_types)
    # Old-style macros
    syntax.c.CHighlighter.keywords.extend(['KRK_METHOD','KRK_FUNC'])
    # New-style macros
    syntax.c.CHighlighter.keywords.extend(['KRK_Method','KRK_Function','KRK_StaticMethod'])

if '/kuroko' in os.getcwd() or '/bim' in os.getcwd():
    enable_kuroko()

if '/bim' in os.getcwd():
    import syntax.c
    syntax.c.CHighlighter.keywords.extend(['BIM_COMMAND','BIM_ACTION'])

def doxy(on=True):
    from syntax.krk import KrkHighlighter
    from syntax.c import CHighlighter
    KrkHighlighter.doxygenDocstrings = bool(on)
    CHighlighter.doxygenDocstrings = bool(on)
    recalc()

from bim import getDocumentText, renderError
let cachedCode = None
import dis

class StaticAnalyzer:
    _opcodeCache = {}

    def __init__(self, real, code):
        self.func = real
        self.code = code

    def checkReferences(self):
        let defined = set()
        let referenced = set()
        let references = {}
        def recursor(func):
            let instructions = dis.examine(func)
            let offset = 0
            for instruction in instructions:
                if isinstance(instruction[2],codeobject):
                    recursor(instruction[2])
                else if instruction[0] in (dis.OP_DEFINE_GLOBAL,dis.OP_DEFINE_GLOBAL_LONG):
                    defined.add(instruction[2])
                else if instruction[0] in (dis.OP_SET_GLOBAL,dis.OP_SET_GLOBAL_LONG,dis.OP_GET_GLOBAL,dis.OP_GET_GLOBAL_LONG):
                    if instruction[2] in referenced:
                    else:
                        referenced.add(instruction[2])
                        references[instruction[2]] = [func._ip_to_line(offset)]
                offset += instruction[1]
        recursor(self.func)
        let undefined = [(x,references[x]) for x in referenced if x not in defined and x not in dir(__builtins__) and x != '__builtins__']
        return undefined

    @classmethod
    def fromCode(cls, code):
        let func
        try:
            func = dis.build(code)
        except SyntaxError as e:
            return (e.lineno, e.colno, e.arg)
        return cls(func, code)

def check(cls):
    let code = getDocumentText()
    if code == cachedCode: return
    cachedCode = code
    let result = StaticAnalyzer.fromCode(getDocumentText())
    if isinstance(result, tuple):
        renderError('')
        renderError(f'\[[0;31mSyntax error on line {result[0]}: {result[2]}')
    else:
        let undef = result.checkReferences()
        if undef:
            renderError('')
            renderError(', '.join(str(x) for x in undef))
        else:
            renderError('')

try:
    from syntax.krk import KrkHighlighter
    if 'doxygenDocstrings' in dir(KrkHighlighter):
        KrkHighlighter.doxygenDocstrings = True
    #KrkHighlighter.checkKrkCode = check
    #KrkHighlighter.enableChecking = True