T3SVIEWS = T3SViews() MESSAGE = Message() def get_or_create_project_and_add_view(view, wizzard=True):
    """
        Returns the project object associated with the file in view.
        Does return None if this file is not a .ts file or from other reasons
    """

    if (view is None
        or view.buffer_id() == 0
        or view.file_name() == ""
        or view.file_name() is None): # closed
        return None
    if view.is_loading():
        return None
    if is_plugin_temporarily_disabled(view):
        return None
    if not is_ts(view):
        return None
    if read_file(view.file_name()) is None:
        return None

    tsconfigdir = find_tsconfigdir(view.file_name())
    if tsconfigdir is None:
        if wizzard:
            Debug('project', "Project without tsconfig.json. Start Wizzard")
            PWizz = ProjectWizzard(view, lambda: get_or_create_project_and_add_view(view))
            PWizz.new_tsconfig_wizzard("No tsconfig.json found. Use this wizzard to create one.")
        return None
    tsconfigfile = os.path.join(tsconfigdir, "tsconfig.json")

    opened_project_with_same_tsconfig = \
         get_first(OPENED_PROJECTS.values(), lambda p: p.tsconfigdir == tsconfigdir)

    if opened_project_with_same_tsconfig is not None:
        Debug('project+', "Already opened project found.")
        opened_project_with_same_tsconfig.open(view)
        return opened_project_with_same_tsconfig
    else:
        # New ts project
        try:
            Debug('notify', "Try open project: %s" % tsconfigdir)

            # Lint tsconfig.json before opening
            can_open_project = True
            try:
                linter = TsconfigLinter(file_name=tsconfigfile)
            except CancelCommand:
                can_open_project = False
            if len(linter.harderrors) > 0:
                can_open_project = False

            if can_open_project:
                new_project = OpenedProject(view)
                if not hasattr(new_project, 'id'):
                    return None
                return new_project
            else:
                show_tsconfig_failed_wizzard(tsconfigfile)
                return None
        except CancelCommand:
            if get_or_create_project_and_add_view(view):
                get_or_create_project_and_add_view(view).close_project()
            return None def project_by_id(project_id):
    if project_id in OPENED_PROJECTS:
        return OPENED_PROJECTS[project_id]
    return None OPENED_PROJECTS = {} def read_file(filename):
    """ returns None or file contents if available """
    filename = os.path.normcase(filename) # back to \\ in nt
    if os.path.isfile(filename):
        try:
            if os.name == 'nt':
                return open(filename, 'r', encoding='utf8').read()
            else:
                return codecs.open(filename, 'r', 'utf-8').read()
        except IOError:
            pass
    return None def fn2k(filename):
    """ shortcut for filename2key """
    return filename2key(filename) def get_file_infos(view):
    return (view.file_name(), get_lines(view), get_content(view)) def get_content_of_view_at(view, min_, lim):
    """ min_ amd lim in typescript-tool coordinates """
    return view.substr(get_region(view, min_, lim)) def get_prefix(token):
    if token in PREFIXES:
        return PREFIXES[token]
    else:
        return '' def catch_CancelCommand(func):
    """ Decorate every command with this one. It will check for
        the plugin disabled flag and catch CancelCommand exceptins. """

    def catcher(*kargs, **kwargs):
        if is_plugin_temporarily_disabled():
            return # do not execute command
        try:
            return func(*kargs, **kwargs)
        except CancelCommand:
            Debug('command', "A COMMAND WAS CANCELED")
            return False
    return catcher class CancelCommand(Exception):
    """ Throw this exception in a command. The decorator
        catch_CancelCommand will catch it and cancel silently """
    pass def Debug(classification, text):
    if 'all' in print_classifications or classification in print_classifications:
        print("ArcticTypescript: %s: %s" % (classification.ljust(8), text))
    if classification not in possible_classifications:
        print("ArcticTypescript: debug: got unknown debug message classification: %s. " \
            "Consider adding this to possible_classifications" % classification)
    sys.stdout.flush() def max_calls(limit = 1500, name=""):
    """Decorator which allows its wrapped function to be called `limit` times"""
    def decorator(func):
        # Disable limit:
        return func
        @wraps(func)
        def wrapper(*args, **kwargs):
            calls = getattr(wrapper, 'calls', 0)
            calls += 1
            setattr(wrapper, 'calls', calls)
            fname = name if name != "" else func.__name__

            if calls == limit + 1:
                Debug('max_calls', "LIMIT !! ## !!: Fkt %s has %i calls, stop" % (fname, calls - 1))

            if calls >= limit + 1:
                return None

            Debug('max_calls', "CALL: Fkt %s has %i calls -> +1" % (fname, calls - 1))

            return func(*args, **kwargs)
        setattr(wrapper, 'calls', 0)
        return wrapper
    return decorator
from threading import Thread
from .display.T3SViews import T3SVIEWS
from .display.Message import MESSAGE
from .system.Project import get_or_create_project_and_add_view, project_by_id
from .system.globals import OPENED_PROJECTS
from .utils.fileutils import read_file, fn2k
from .utils.viewutils import get_file_infos, get_content_of_view_at
from .utils.uiutils import get_prefix
from .utils.CancelCommand import catch_CancelCommand, CancelCommand
from .utils import Debug, max_calls
import sublime
import sublime_plugin
import os
import re
import traceback
        if view.is_loading():
            sublime.set_timeout(lambda: self.open_view(view, definition), 100)
            return
        else:
            start_line = definition['min']['line']
            end_line = definition['lim']['line']
            left = definition['min']['character']
            right = definition['lim']['character']

            a = view.text_point(start_line-1, left-1)
            b = view.text_point(end_line-1, right-1)
            region = sublime.Region(a, b)

            Debug('focus', 'Z focus view %i' % view.id())
            sublime.active_window().focus_view(view)
            view.show_at_center(region)

            sel = view.sel()
            sel.clear()
            sel.add(a)

            view.add_regions('typescript-definition', [region],
                             'comment', 'dot', sublime.DRAW_NO_FILL)


# ################################# REFACTORING ############################

class TypescriptRefactor(sublime_plugin.TextCommand):

    @catch_CancelCommand
    def run(self, edit_token):
        project = get_or_create_project_and_add_view(self.view)
        if project:
            project.assert_initialisation_finished()

            if not project.get_setting('enable_refactoring'):
                return

            # Position of activation.
            pos = self.view.sel()[0].begin()
            (line, col) = self.view.rowcol(pos)
            _view = self.view

            project.tsserver.references(self.view.file_name(), line, col, callback=self.async_react)

    @catch_CancelCommand
    def async_react(self, refs, filename, line, col):
        if refs is None or len(refs) == 0:
            return

        view = sublime.active_window().active_view()
        project = get_or_create_project_and_add_view(view)

        if not project:
            return

        if self.selection_has_changed(filename, line, col):
            return

        Debug('refactor', refs)
        #{'lineText': '        let total = 0;',
        # 'file': '/home/daniel/.config/sublime-text-3/Packages/ArcticTypescript/tests/TDDTesting/main.ts',
        # 'min': {'character': 13,
        #         'line': 43},
        # 'lim': {'character': 18,
        #         'line': 43},
        # 'ref': {'textSpan': {'start': 760,
        #                      'length': 5},
        #         'fileName': '/home/daniel/.config/sublime-text-3/Packages/ArcticTypescript/tests/TDDTesting/main.ts',
        #         'isWriteAccess': True}}


        refactor_member = self.get_entire_member_name(refs)
        if not refactor_member:
            return

        Debug('refactor', refactor_member)

        sublime.active_window().show_input_panel(
            'Refactoring %s (found %i times) to:' % (refactor_member, len(refs)),
            refactor_member,
            lambda new_name: sublime.run_command("typescript_apply_refactor",
                {"project":project, "refs":refs, "old_name":refactor_member, "new_name":new_name}), # require edit token
            None, # change
            None) # camcel
            ## TODO: keine Objekte ins run_command -> verweise bze hashes und die refs temporär im project abspeicern

    def selection_has_changed(self, orig_filename, orig_line, orig_col):
        """ Return True if active selection has changed """

        view = sublime.active_window().active_view()
        if orig_filename != view.file_name():
            return True

        current_pos = view.sel()[0].begin()
        (current_line, current_col) = view.rowcol(current_pos)

        if orig_col != current_col or orig_line != current_line:
            return True

        return False


    def get_entire_member_name(self, references):
        """ returns the complete member name of the refactored member """
        ref = references[0]
        return ref['lineText'][ref['min']['character']-1:ref['lim']['character']-1]



class TypescriptApplyRefactor(sublime_plugin.TextCommand):
    def run(self, edit_token, project, refs, old_name, new_name):
        project.do_refactor(refs, refactor_member, new_name, edit_token)


# ################################# OPEN OUTLINE PANEL #########################

# (via shortkey / public command)
class TypescriptStructure(sublime_plugin.TextCommand):
    """ this command opens and focus the structure/outline view """

    @catch_CancelCommand