<commit_before>from __future__ import print_function

import webbrowser
import os, os.path
import subprocess
import json

import sublime, sublime_plugin

try:     # ST3
    from .elm_project import ElmProject
except:  # ST2
    from elm_project import ElmProject

LOOKUPS = {}

def join_qualified(region, view):
    """
    Given a region, expand outward on periods to return a new region defining
    the entire word, in the context of Elm syntax.

    For example, when the region encompasses the 'map' part of a larger
    'Dict.map' word, this function will return the entire region encompassing
    'Dict.map'. The same is true if the region is encompassing 'Dict'.

    Recursively expands outward in both directions, correctly returning longer
    constructions such as 'Graphics.Input.button'
    """
    starting_region = region
    prefix = view.substr(region.a - 1)
    suffix = view.substr(region.b)
    if prefix == '.':
        region = region.cover(view.word(region.a - 2))
    if suffix == '.':
        region = region.cover(view.word(region.b + 1))

    if region == starting_region:
        return region
    else:
        return join_qualified(region, view)

def get_word_under_cursor(view):
    sel = view.sel()[0]
    region = join_qualified(view.word(sel), view)
    return view.substr(region).strip()     

def get_type(view):
    """
    Given a view, return the type signature of the word under the cursor,
    if found. If no type is found, return an empty string.
    """
    sel = view.sel()[0]
    region = join_qualified(view.word(sel), view)
    scope = view.scope_name(region.b)
    if scope.find('source.elm') != -1 and scope.find('string') == -1 and scope.find('comment') == -1:
        filename = view.file_name()
        word = view.substr(region).strip()
        sublime.set_timeout_async(lambda: search_and_set_status_message(filename, word, 0), 0)
        return ''

def search_and_set_status_message(filename, query, tries):
    """
    Given a filename and a query, look up in the in-memory dict of values
    pulled from elm oracle to find a match. If a match is found, display
    the type signature in the status bar.
    """
    global LOOKUPS
    if len(query) == 0:
        return None
    if filename not in LOOKUPS.keys():
        if tries >= 10:
            return None
        else:
            # if the filename is not found loaded into memory, it's probably being
            # loaded into memory right now. Try 10 more times at 100ms intervals
            # and if it still isn't loaded, there's likely a problem we can't fix
            # here.
            sublime.set_timeout_async(search_and_set_status_message(filename, query, tries + 1), 100)
    else:
        data = LOOKUPS[filename]
        if len(data) > 0:
            for item in data:
                if item['name'] == query.split('.')[-1]:
                    type_signature = item['fullName'] + ' : ' + item['signature']
                    sublime.status_message(type_signature)
                    break
        return None     

def get_matching_names(filename, prefix):
    """
    Given a file name and a search prefix, return a list of matching
    completions from elm oracle.
    """
    global LOOKUPS
    if filename not in LOOKUPS.keys():
        return None
    else:
        data = LOOKUPS[filename]
        completions = {(v['fullName'] + '\t' + v['signature'], v['fullName']) 
            for v in data 
            if v['fullName'].startswith(prefix) or v['name'].startswith(prefix)}
        return [[v[0], v[1]] for v in completions]

def explore_package(filename, package_name):
    global LOOKUPS
    if filename not in LOOKUPS.keys() or len(package_name) == 0:
        return None
    elif package_name[0].upper() != package_name[0]:
        sublime.status_message('This is not a package!')
        return None
    else:
        def open_link(items, i):
            if i == -1:
                return None
            else:
                open_in_browser(items[i][3])
        data = [[v['fullName'], v['signature'], v['comment'], v['href']] 
            for v in LOOKUPS[filename] 
            if v['fullName'].startswith(package_name)]
        panel_items = [v[:3] for v in data]
        sublime.active_window().show_quick_panel(panel_items, lambda i: open_link(data, i))

def open_in_browser(url):
    webbrowser.open_new_tab(url)        

def load_from_oracle(filename):
    """
    Loads all data about the current file from elm oracle and adds it
    to the LOOKUPS global dictionary.
    """
    global LOOKUPS
    project = ElmProject(filename)
    os.chdir(project.working_dir)
    p = subprocess.Popen('elm-oracle ' + filename + ' ""', stdout=subprocess.PIPE, shell=True)
    output = p.communicate()[0].strip()
    try:
        data = json.loads(output.decode('utf-8'))
    except ValueError:<commit_msg>Add slightly prettier doc printing...<commit_after>from __future__ import print_function

import webbrowser
import os, os.path
import subprocess
import json

import sublime, sublime_plugin

try:     # ST3
    from .elm_project import ElmProject
except:  # ST2
    from elm_project import ElmProject

LOOKUPS = {}

def join_qualified(region, view):
    """
    Given a region, expand outward on periods to return a new region defining
    the entire word, in the context of Elm syntax.

    For example, when the region encompasses the 'map' part of a larger
    'Dict.map' word, this function will return the entire region encompassing
    'Dict.map'. The same is true if the region is encompassing 'Dict'.

    Recursively expands outward in both directions, correctly returning longer
    constructions such as 'Graphics.Input.button'
    """
    starting_region = region
    prefix = view.substr(region.a - 1)
    suffix = view.substr(region.b)
    if prefix == '.':
        region = region.cover(view.word(region.a - 2))
    if suffix == '.':
        region = region.cover(view.word(region.b + 1))

    if region == starting_region:
        return region
    else:
        return join_qualified(region, view)

def get_word_under_cursor(view):
    sel = view.sel()[0]
    region = join_qualified(view.word(sel), view)
    return view.substr(region).strip()     

def get_type(view):
    """
    Given a view, return the type signature of the word under the cursor,
    if found. If no type is found, return an empty string.
    """
    sel = view.sel()[0]
    region = join_qualified(view.word(sel), view)
    scope = view.scope_name(region.b)
    if scope.find('source.elm') != -1 and scope.find('string') == -1 and scope.find('comment') == -1:
        filename = view.file_name()
        word = view.substr(region).strip()
        sublime.set_timeout_async(lambda: search_and_set_status_message(filename, word, 0), 0)
        return ''

def search_and_set_status_message(filename, query, tries):
    """
    Given a filename and a query, look up in the in-memory dict of values
    pulled from elm oracle to find a match. If a match is found, display
    the type signature in the status bar.
    """
    global LOOKUPS
    if len(query) == 0:
        return None
    if filename not in LOOKUPS.keys():
        if tries >= 10:
            return None
        else:
            # if the filename is not found loaded into memory, it's probably being
            # loaded into memory right now. Try 10 more times at 100ms intervals
            # and if it still isn't loaded, there's likely a problem we can't fix
            # here.
            sublime.set_timeout_async(search_and_set_status_message(filename, query, tries + 1), 100)
    else:
        data = LOOKUPS[filename]
        if len(data) > 0:
            for item in data:
                if item['name'] == query.split('.')[-1]:
                    type_signature = item['fullName'] + ' : ' + item['signature']
                    sublime.status_message(type_signature)
                    break
        return None     

def get_matching_names(filename, prefix):
    """
    Given a file name and a search prefix, return a list of matching
    completions from elm oracle.
    """
    global LOOKUPS
    if filename not in LOOKUPS.keys():
        return None
    else:
        data = LOOKUPS[filename]
        completions = {(v['fullName'] + '\t' + v['signature'], v['fullName']) 
            for v in data 
            if v['fullName'].startswith(prefix) or v['name'].startswith(prefix)}
        return [[v[0], v[1]] for v in completions]

def explore_package(filename, package_name):
    global LOOKUPS
    if filename not in LOOKUPS.keys() or len(package_name) == 0:
        return None
    elif package_name[0].upper() != package_name[0]:
        sublime.status_message('This is not a package!')
        return None
    else:
        def open_link(items, i):
            if i == -1:
                return None
            else:
                open_in_browser(items[i][3])
        data = [[v['fullName'], v['signature'], v['comment'], v['href']] 
            for v in LOOKUPS[filename] 
            if v['fullName'].startswith(package_name)]
        # all items must be the same number of rows
        n = 75
        panel_items = [v[:2] + [v[2][:n]] + [v[2][n:2*n]] + [v[2][2*n:]] for v in data]
        sublime.active_window().show_quick_panel(panel_items, lambda i: open_link(data, i))

def open_in_browser(url):
    webbrowser.open_new_tab(url)        

def load_from_oracle(filename):
    """
    Loads all data about the current file from elm oracle and adds it
    to the LOOKUPS global dictionary.
    """
    global LOOKUPS
    project = ElmProject(filename)
    os.chdir(project.working_dir)
    p = subprocess.Popen('elm-oracle ' + filename + ' ""', stdout=subprocess.PIPE, shell=True)
    output = p.communicate()[0].strip()
    try:
        data = json.loads(output.decode('utf-8'))
    except ValueError:
{'fraction_non_alphanumeric': 0.10697957939652544, 'fraction_numerical': 0.008026008330793458, 'mean_word_length': 2.5499459069599713, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1253557', 'n_tokens_mistral': 3023, 'n_tokens_neox': 2910, 'n_words': 931}