Exemple #1
0
    def on_query_context(self, view, key, _operator, _operand, _matchall):
        if Settings.COMPONENT_DEBUG.event_viewer:
            print('{0} key = {1}.'.format(
                type(self).__name__ + '.on_query_context', key))
        retval = None
        if key == 'haskell_autofix':
            retval = view.settings().get('autofix')
        elif key == 'auto_completion_popup':
            retval = Settings.PLUGIN.auto_completion_popup
        elif key == 'haskell_source':
            retval = Common.is_haskell_source(view)
        elif key == 'haskell_source_or_repl':
            retval = Common.is_haskell_source(view) or Common.is_haskell_repl(
                view)
        elif key == 'haskell_repl':
            retval = Common.is_haskell_repl(view)
        elif key == 'haskell_symbol_info':
            retval = Common.is_haskell_symbol_info(view)
        elif key == 'cabal_source':
            retval = Common.is_cabal_source(view)
        elif key == 'scanned_source':
            retval = self.is_scanned_source(view)
        elif key == 'in_project':
            retval = self.is_in_project(view)
        elif key == "is_module_completion" or key == "is_import_completion":
            # Completion context is the only branch here where a backend is needed.
            retval = False
            with self.backend_mgr:
                project_dir, project_name = Common.locate_cabal_project_from_view(
                    view)
                region = view.sel()[0]
                if region.a == region.b:
                    word_region = view.word(region)
                    preline = Common.get_line_contents_before_region(
                        view, word_region)
                    preline += self.COMPLETION_CHARS[key]
                    qsymbol = Common.get_qualified_symbol(preline)
                    if qsymbol.module:
                        mod_completions = self.autocompleter.get_current_module_completions(
                            project_name, project_dir)
                        if qsymbol.is_import_list:
                            retval = qsymbol.module in mod_completions
                        else:
                            retval = [
                                m for m in mod_completions
                                if m.startswith(qsymbol.module)
                            ] != []

        return retval
Exemple #2
0
 def on_selection_modified(self, view):
     if Common.is_haskell_source(view) and view.file_name():
         srcfile = view.file_name()
         if SourceHaskellTypeCache().has(
                 srcfile) and SourceHaskellTypeCache().shown(srcfile):
             view.run_command('sublime_haskell_show_all_types',
                              {'filename': srcfile})
Exemple #3
0
 def on_hover(self, view, point, hover_zone):
     # Note: view.file_name() is not set in certain views, such as the "Haskell Show Types Panel". Avoid
     # generating lookup errors, which are logged in the console window (for better or worse.)
     if Common.is_haskell_source(view) and view.file_name():
         # Ensure that we never block the Python main thread.
         info_pop = InfoPop.SublimeHaskellHoverPopup(view, view.file_name(), point, hover_zone)
         Utils.run_async('SublimeHaskellPopup.on_hover', info_pop.do_hover)
Exemple #4
0
 def activated_worker():
     with self.backend_mgr:
         self.assoc_to_project(view, filename)
         project_name = Common.locate_cabal_project_from_view(view)[1]
         if Common.is_haskell_source(view):
             self.autocompleter.generate_completions_cache(
                 project_name, filename)
Exemple #5
0
    def on_load(self, view):
        filename = view.file_name()
        if filename is None or not Common.is_inspected_source(view):
            return

        if Settings.COMPONENT_DEBUG.event_viewer:
            print('{0} is_inspected_source {1}.'.format(
                type(self).__name__ + ".on_load", filename))

        self.assoc_to_project(view, filename)
        project_name = Common.locate_cabal_project_from_view(view)[1]
        self.rescan_source(project_name, filename)

        if Common.is_haskell_source(view):
            if Settings.COMPONENT_DEBUG.event_viewer:
                print('{0} is_haskell_source {1}.'.format(
                    type(self).__name__ + ".on_load", filename))

            view.settings().set('translate_tabs_to_spaces', True)
            if Settings.PLUGIN.use_improved_syntax:
                name = os.path.basename(filename.lower())
                if Settings.PLUGIN.use_improved_syntax and (
                        name.endswith(".hs") or name.endswith(".hsc")):
                    view.settings().set(
                        'syntax',
                        'Packages/SublimeHaskell/Syntaxes/Haskell-SublimeHaskell.tmLanguage'
                    )
Exemple #6
0
def get_projects():
    if hsdev.agent_connected():
        folders = sublime.active_window().folders()
        view_files = [
            v.file_name() for v in sublime.active_window().views()
            if (Common.is_haskell_source(v) or Common.is_cabal_source(v))
            and v.file_name()
        ]

        def npath(path):
            return os.path.normcase(os.path.normpath(path))

        def childof(path, prefix):
            return npath(path).startswith(npath(prefix))

        return dict((info['name'], info) for info in filter(
            lambda p: any([childof(p['path'], f) for f in folders]) or any(
                [childof(src, p['path']) for src in view_files]), (
                    hsdev.client.list_projects() or [])))
    else:
        folder_files = [src for f in sublime.active_window().folders() for src in Common.list_files_in_dir_recursively(f) \
                        if os.path.splitext(src)[1] in [".hs", ".cabal"]
                       ]
        view_files = [
            v.file_name() for v in sublime.active_window().views()
            if (Common.is_haskell_source(v) or Common.is_cabal_source(v))
            and v.file_name()
        ]
        src_files = list(
            map(lambda p: os.path.normcase(os.path.normpath(p)),
                folder_files + view_files))
        active_projects = []
        while src_files:
            src = src_files.pop()
            proj_dir, proj_name = Common.get_cabal_project_dir_and_name_of_file(
                src)
            if proj_dir:
                active_projects.append((proj_name, proj_dir))
                src_files = [
                    f for f in src_files if not f.startswith(proj_dir)
                ]

        return dict((name, {
            'name': name,
            'path': path
        }) for name, path in active_projects)
Exemple #7
0
    def on_modified(self, view):
        filename = view.file_name()
        if filename is None or not Common.is_haskell_source(view):
            return

        if Settings.COMPONENT_DEBUG.event_viewer:
            print('{0} invoked.'.format(type(self).__name__ + ".on_modified"))

        if Settings.PLUGIN.lint_check_fly:
            Utils.run_async('fly check', self.fly, view)
        self.type_cache.remove(filename)
Exemple #8
0
    def on_query_completions(self, view, prefix, locations):
        # Defer starting the backend until as late as possible...
        if Settings.COMPONENT_DEBUG.event_viewer:
            print('{0} invoked (prefix: {1}).'.format(type(self).__name__ + '.on_query_completions', prefix))

        if not Common.is_haskell_source(view):
            return []

        completions = None
        with self.backend_mgr:
            begin_time = time.clock()

            # Only suggest symbols if the current file is part of a Cabal project.
            filename = view.file_name()
            line_contents = Common.get_line_contents(view, locations[0])
            project_name = Common.locate_cabal_project_from_view(view)[1]
            completion_flags = sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS

            curselector = view.scope_name(locations[0])
            if self.LANGUAGE_RE.search(line_contents):
                completions = self.autocompleter.get_lang_completions(project_name)
            elif self.OPTIONS_GHC_RE.search(line_contents):
                completions = self.autocompleter.get_flag_completions(project_name)
            elif 'meta.import.haskell' in curselector:
                # Inside an import: Complete the imported module name:
                completions = self.autocompleter.get_import_completions(project_name, filename, locations, line_contents)
            elif 'meta.declaration.exports.haskell' in curselector:
                # Export list
                export_module = Autocomplete.EXPORT_MODULE_RE.search(line_contents)
                if export_module:
                    # qsymbol = Common.get_qualified_symbol_at_region(view, view.sel()[0])
                    # TODO: Implement
                    pass
            else:
                # Add current file's completions:
                completions = self.autocompleter.get_completions(view, locations)
                if not Settings.PLUGIN.inhibit_completions:
                    completion_flags = 0

            end_time = time.clock()
            Logging.log('time to get completions: {0} seconds'.format(end_time - begin_time), Logging.LOG_INFO)

        # Don't put completions with special characters (?, !, ==, etc.)
        # into completion because that wipes all default Sublime completions:
        # See http://www.sublimetext.com/forum/viewtopic.php?t=8659
        # TODO: work around this
        # comp = [c for c in completions if NO_SPECIAL_CHARS_RE.match(c[0].split('\t')[0])]
        # if Settings.PLUGIN.inhibit_completions and len(comp) != 0:
        #     return (comp, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
        # return comp

        return (completions, completion_flags)  # if completions else []
Exemple #9
0
    def get_projects(self):
        folders = sublime.active_window().folders()
        view_files = [v.file_name() for v in sublime.active_window().views()
                      if (Common.is_haskell_source(v) or Common.is_cabal_source(v)) and v.file_name()]

        def childof(path, prefix):
            return Utils.normalize_path(path).startswith(Utils.normalize_path(prefix))

        def relevant_project(proj):
            return any([childof(proj['path'], f) for f in folders]) or any([childof(src, proj['path']) for src in view_files])

        projects = BackendMgr.active_backend().list_projects() or []
        return dict((info['name'], info) for info in projects if relevant_project(info))
Exemple #10
0
    def on_post_save(self, view):
        filename = view.file_name()
        if filename is not None and Common.is_inspected_source(view):
            if Settings.COMPONENT_DEBUG.event_viewer:
                print('{0} invoked.'.format(type(self).__name__ + ".on_post_save"))

            if Common.is_haskell_source(view):
                self.type_cache.remove(filename)
                self.trigger_build(view)

                if Settings.PLUGIN.prettify_on_save:
                    if Settings.PLUGIN.prettify_executable == 'stylish-haskell':
                        view.run_command('sublime_haskell_stylish')
                    elif Settings.PLUGIN.prettify_executable == 'hindent':
                        view.run_command('sublime_haskell_hindent')

            # Ensure that the source scan happens after trigger_build -- the inspector is active, so the SublimeHaskell
            # commands that we try to execute end up being disabled.
            project_name = Common.locate_cabal_project_from_view(view)[1]
            Utils.run_async('rescan source {0}/{1}'.format(project_name, filename), self.rescan_source, project_name, filename)
Exemple #11
0
 def is_visible(self):
     return Common.is_haskell_symbol_info(self.view) or \
            Common.is_haskell_source(self.view) or \
            Common.is_haskell_repl(self.view)
Exemple #12
0
    def on_modified(self, view):
        lint_check_fly = Settings.PLUGIN.lint_check_fly

        if lint_check_fly and Common.is_haskell_source(
                view) and view.file_name():
            self.fly_agent.fly(view)
Exemple #13
0
    def on_hover(self, view, point, hover_zone):
        if not Common.is_haskell_source(view):
            return

        self.view = view
        self.current_file_name = self.view.file_name()
        # If the column is needed: (line, column) = self.view.rowcol(point) [remove subscript]
        line = self.view.rowcol(point)[0]
        self.decl = None
        self.typed_expr = None

        if hover_zone == sublime.HOVER_TEXT:
            qsymbol = Common.get_qualified_symbol_at_point(self.view, point)
            module_word = qsymbol.module
            ident = qsymbol.name

            if ident is None and module_word:  # TODO: Any ideas for popup about module?
                pass

            if ident:
                self.whois_name = qsymbol.qualified_name()
                self.full_name = qsymbol.full_name()

                # Try get type of hovered symbol
                self.point = point
                self.typed_expr = None
                if types.FILE_TYPES.has(self.current_file_name):
                    self.typed_expr = self.get_type(
                        types.FILE_TYPES.get(self.current_file_name))
                else:
                    types.get_types(self.current_file_name, self.on_types)

                # Try whois
                self.suggest_import = False
                self.decl = Utils.head_of(
                    hsdev.client.whois(self.whois_name,
                                       self.current_file_name))

                if not self.decl:
                    self.suggest_import = True
                    self.decl = Utils.head_of(
                        hsdev.client.lookup(self.full_name,
                                            self.current_file_name))

                self.create_symbol_popup()

        elif hover_zone == sublime.HOVER_GUTTER:
            self.view = view
            self.current_file_name = self.view.file_name()
            errs = list(
                filter(lambda e: e.region.start.line == line,
                       parseoutput.errors_for_view(self.view)))
            if errs:
                popup_parts = [
                    SUBHASK_STYLES.gen_style(
                        self.view.settings().get('color_scheme'))
                ]
                for err in errs:
                    msg = UnicodeOpers.use_unicode_operators(
                        symbols.escape_text(err.message))
                    # Decorate first word with style
                    decors = {
                        'Error': 'error',
                        'Warning': 'warning',
                        'Hint': 'hint'
                    }
                    for dec, dec_style in decors.items():
                        msg = msg.replace(
                            dec, u'<span class="{0}">{1}</span>'.format(
                                dec_style, dec))
                    popup_parts.append(u'<p>{0}</p>'.format(msg))
                    if err.correction is not None:
                        popup_parts.append(err.correction.popup())
                popup_text = u''.join(popup_parts)
                self.view.show_popup(popup_text,
                                     sublime.HIDE_ON_MOUSE_MOVE_AWAY, point,
                                     600, 600, self.on_navigate, self.on_hide)
 def is_visible(self):
     return Common.is_haskell_source(self.view) and super().is_visible()
Exemple #15
0
 def is_enabled(self):
     return Common.is_haskell_source(
         self.view) and self.view.file_name() is not None
Exemple #16
0
 def is_enabled(self):
     return Common.is_haskell_source(self.view) and \
            self.view.file_name() is not None and \
            FILE_TYPES.has(self.view.file_name()) and \
            FILE_TYPES.shown(self.view.file_name())
Exemple #17
0
 def is_enabled(self):
     return Common.is_haskell_source(self.view) or Common.is_haskell_repl(self.view) or \
            (Common.is_haskell_symbol_info(self.view) and self.view.settings().get('location'))
Exemple #18
0
 def is_enabled(self):
     return Common.is_haskell_source(self.view) and \
            self.view.file_name() is not None and \
            SourceHaskellTypeCache().has(self.view.file_name()) and \
            SourceHaskellTypeCache().shown(self.view.file_name())
Exemple #19
0
 def on_selection_modified(self, view):
     if TOGGLE_SYMBOL_INFO and Common.is_haskell_source(view) and view.file_name():
         view.run_command('sublime_haskell_symbol_info', {'no_browse': True})
Exemple #20
0
 def is_visible(self):
     return Common.is_haskell_source(self.view) or Common.is_haskell_repl(self.view)
Exemple #21
0
 def on_selection_modified(self, view):
     if Common.is_haskell_source(view) and \
        view.file_name() and FILE_TYPES.has(view.file_name()) and \
        FILE_TYPES.shown(view.file_name()):
         view.run_command('sublime_haskell_show_all_types', {'filename': view.file_name()})
Exemple #22
0
 def is_enabled(self):
     return (self.view.settings().get('package') is not None) or \
            Common.is_haskell_source(self.view) or \
            Common.is_haskell_repl(self.view)
Exemple #23
0
 def is_enabled(self):
     return Common.is_haskell_source(None)