def init_ghcmod_completions(self): # Init LANGUAGE completions self.language_completions = call_ghcmod_and_wait(['lang']).split('\n') log("Reading LANGUAGE completions from ghc-mod") # Init import module completion self.module_completions = call_ghcmod_and_wait(['list']).split('\n')
def init_ghcmod_completions(self): if not get_setting('enable_ghc_mod'): return sublime.status_message('SublimeHaskell: Updating ghc_mod completions...') # Init LANGUAGE completions autocompletion.language_completions = call_ghcmod_and_wait(['lang']).splitlines() # Init import module completion autocompletion.module_completions = set(call_ghcmod_and_wait(['list']).splitlines()) sublime.status_message('SublimeHaskell: Updating ghc_mod completions ' + u" \u2714")
def wait_ghcmod_and_parse(view, file_dir, msg, cmds_with_args, alter_messages_cb): sublime.set_timeout(lambda: hide_output(view), 0) exit_success = True parsed_messages = [] for (cmd, args) in cmds_with_args: stdout = call_ghcmod_and_wait(args, file_dir) # stdout contains NULL as line endings within one message # error_output_regex using indents to determine one message scope # Replace NULLs to indents out = stdout.replace('\0', '\n ').decode('utf-8') exit_success = exit_success and len(out) == 0 parsed = parse_output_messages(file_dir, out) for p in parsed: parsed_messages.append((cmd, p)) exit_code = 0 if exit_success else 1 if alter_messages_cb: alter_messages_cb(parsed_messages) concated_messages = map(lambda m: m[1], parsed_messages) output_text = format_output_messages(concated_messages) show_output_result_text(view, msg, output_text, exit_code, file_dir) sublime.set_timeout(lambda: mark_messages_in_views(concated_messages), 0)
def ghcmod_get_type_of_cursor(self): view = self.view filename = str(view.file_name()) row, col = view.rowcol(view.sel()[0].a) row1, col1 = row + 1, col + 1 # ghc-mod uses rows/cols starting with 1 module_region = view.find(MODULE_RE_STR, 0) if module_region is None: sublime.status_message( "SublimeHaskell: Could not determine module name!") return None # RE must match; there is only one group in the RE. module = MODULE_RE.match(view.substr(module_region)).group(1) ghcmod_args = ['type', filename, module, str(row1), str(col1)] out = call_ghcmod_and_wait(ghcmod_args) if not out: sublime.status_message("ghc-mod %s returned nothing" % ' '.join(ghcmod_args)) return None # ghc-mod type returns the type of the expression at at the given row/col. # It can return multiple lines, extending the expression scope by one level each. # The last line belongs to the toplevel expression. types = map(parse_ghc_mod_type_line, out.strip().split('\n')) result_type = types[0]['type'] # innermost expression's type if not result_type: sublime.error_message("ghc-mod type returned unexpected output") return None return result_type
def ghcmod_get_type_of_cursor(self): view = self.view filename = str(view.file_name()) row, col = view.rowcol(view.sel()[0].a) row1, col1 = row + 1, col + 1 # ghc-mod uses rows/cols starting with 1 module_region = view.find(MODULE_RE_STR, 0) if module_region is None: sublime.status_message("SublimeHaskell: Could not determine module name!") return None # RE must match; there is only one group in the RE. module = MODULE_RE.match(view.substr(module_region)).group(1) ghcmod_args = ['type', filename, module, str(row1), str(col1)] out = call_ghcmod_and_wait(ghcmod_args) if not out: sublime.status_message("ghc-mod %s returned nothing" % ' '.join(ghcmod_args)) return None # ghc-mod type returns the type of the expression at at the given row/col. # It can return multiple lines, extending the expression scope by one level each. # The last line belongs to the toplevel expression. types = map(parse_ghc_mod_type_line, out.strip().split('\n')) result_type = types[0]['type'] # innermost expression's type if not result_type: sublime.error_message("ghc-mod type returned unexpected output") return None return result_type
def ghcmod_browse_module(module_name, cabal = None, use_ghc_package = False): """ Returns symbols.Module with all declarations """ contents = None if use_ghc_package: contents = call_ghcmod_and_wait(['-g', '-package ghc','browse', '-d', module_name], cabal = cabal).splitlines() else: contents = call_ghcmod_and_wait(['browse', '-d', module_name], cabal = cabal).splitlines() # Adding empty modules into cache greatly speeds up loading standard modules cache # if not contents: # return None m = symbols.Module(module_name, cabal = cabal) functionRegex = r'(?P<name>\w+)\s+::\s+(?P<type>.*)' typeRegex = r'(?P<what>(class|type|data|newtype))\s+(?P<name>\w+)(\s+(?P<args>\w+(\s+\w+)*))?' def toDecl(line): matched = re.search(functionRegex, line) if matched: return symbols.Function(matched.group('name'), matched.group('type')) else: matched = re.search(typeRegex, line) if matched: decl_type = matched.group('what') decl_name = matched.group('name') decl_args = matched.group('args') decl_args = decl_args.split() if decl_args else [] if decl_type == 'class': return symbols.Class(decl_name, None, decl_args) elif decl_type == 'data': return symbols.Data(decl_name, None, decl_args) elif decl_type == 'type': return symbols.Type(decl_name, None, decl_args) elif decl_type == 'newtype': return symbols.Newtype(decl_name, None, decl_args) else: return symbols.Declaration(line) decls = map(toDecl, contents) for decl in decls: m.add_declaration(decl) return m
def ghcmod_info(filename, module_name, symbol_name, cabal = None): """ Uses ghc-mod info filename module_name symbol_name to get symbol info """ contents = call_ghcmod_and_wait(['info', filename, module_name, symbol_name], filename = filename, cabal = cabal) # TODO: Returned symbol doesn't contain location # But in fact we use ghcmod_info only to retrieve type of symbol return parse_info(symbol_name, contents)
def ghcmod_type(filename, module_name, line, column, cabal=None): """ Uses ghc-mod type to infer type """ return call_ghcmod_and_wait( ['type', filename, module_name, str(line), str(column)], filename=filename, cabal=cabal)
def wait_ghcmod_and_parse(view, filename, msg, cmds_with_args, alter_messages_cb): sublime.set_timeout(lambda: hide_output(view), 0) parsed_messages = [] file_dir = os.path.dirname(filename) all_cmds_successful = True all_cmds_outputs = [] for (cmd, args) in cmds_with_args: stdout = call_ghcmod_and_wait(args, filename) # stdout contains NULL as line endings within one message # error_output_regex using indents to determine one message scope # Replace NULLs to indents out1 = stdout.replace('\0', '\n ') # Hlint outputs Error instead Warning for tips # so lets replace them out = out1.replace('Error', 'Warning') success = len(out.strip()) == 0 if not success: all_cmds_outputs.append(out) log(u"ghc-mod %s didn't exit with success on '%s'" % (u' '.join(cmd), filename)) all_cmds_successful &= success parsed = parse_output_messages(file_dir, out) for p in parsed: parsed_messages.append((cmd, p)) if alter_messages_cb: alter_messages_cb(parsed_messages) concated_messages = [m[1] for m in parsed_messages] # Set global error list set_global_error_messages(concated_messages) sublime.set_timeout(lambda: mark_messages_in_views(concated_messages), 0) output_text = (format_output_messages(concated_messages) if parsed_messages else '\n'.join(all_cmds_outputs)) exit_code = 0 if all_cmds_successful else 1 show_output_result_text(view, msg, output_text, exit_code, file_dir)
def wait_ghcmod_and_parse(view, filename, msg, cmds_with_args, alter_messages_cb): sublime.set_timeout(lambda: hide_output(view), 0) parsed_messages = [] file_dir = os.path.dirname(filename) all_cmds_successful = True all_cmds_outputs = [] for (cmd, args) in cmds_with_args: stdout = call_ghcmod_and_wait(args, filename) # stdout contains NULL as line endings within one message # error_output_regex using indents to determine one message scope # Replace NULLs to indents out = stdout.replace('\0', '\n ') success = len(out.strip()) == 0 if not success: all_cmds_outputs.append(out) log(u"ghc-mod %s didn't exit with success on '%s'" % (u' '.join(cmd), filename)) all_cmds_successful &= success parsed = parse_output_messages(file_dir, out) for p in parsed: parsed_messages.append((cmd, p)) if alter_messages_cb: alter_messages_cb(parsed_messages) concated_messages = [m[1] for m in parsed_messages] # Set global error list set_global_error_messages(concated_messages) sublime.set_timeout(lambda: mark_messages_in_views(concated_messages), 0) output_text = (format_output_messages(concated_messages) if parsed_messages else '\n'.join(all_cmds_outputs)) exit_code = 0 if all_cmds_successful else 1 show_output_result_text(view, msg, output_text, exit_code, file_dir)
def ghcmod_browse_module(module_name, cabal = None): """ Returns symbols.Module with all declarations """ contents = call_ghcmod_and_wait(['browse', '-d', module_name], cabal = cabal).splitlines() if not contents: return None m = symbols.Module(module_name, cabal = cabal) functionRegex = r'(?P<name>\w+)\s+::\s+(?P<type>.*)' typeRegex = r'(?P<what>(class|type|data|newtype))\s+(?P<name>\w+)(\s+(?P<args>\w+(\s+\w+)*))?' def toDecl(line): matched = re.search(functionRegex, line) if matched: return symbols.Function(matched.group('name'), matched.group('type')) else: matched = re.search(typeRegex, line) if matched: decl_type = matched.group('what') decl_name = matched.group('name') decl_args = matched.group('args') decl_args = decl_args.split() if decl_args else [] if decl_type == 'class': return symbols.Class(decl_name, None, decl_args) elif decl_type == 'data': return symbols.Data(decl_name, None, decl_args) elif decl_type == 'type': return symbols.Type(decl_name, None, decl_args) elif decl_type == 'newtype': return symbols.Newtype(decl_name, None, decl_args) else: return symbols.Declaration(line) decls = map(toDecl, contents) for decl in decls: m.add_declaration(decl) return m
def ghcmod_browse_module(module_name, cabal=None): """ Returns symbols.Module with all declarations """ contents = call_ghcmod_and_wait(["browse", "-d", module_name], cabal=cabal).splitlines() if not contents: return None m = symbols.Module(module_name, cabal=cabal) functionRegex = r"(?P<name>\w+)\s+::\s+(?P<type>.*)" typeRegex = r"(?P<what>(class|type|data|newtype))\s+(?P<name>\w+)(\s+(?P<args>\w+(\s+\w+)*))?" def toDecl(line): matched = re.search(functionRegex, line) if matched: return symbols.Function(matched.group("name"), matched.group("type")) else: matched = re.search(typeRegex, line) if matched: decl_type = matched.group("what") decl_name = matched.group("name") decl_args = matched.group("args") decl_args = decl_args.split() if decl_args else [] if decl_type == "class": return symbols.Class(decl_name, None, decl_args) elif decl_type == "data": return symbols.Data(decl_name, None, decl_args) elif decl_type == "type": return symbols.Type(decl_name, None, decl_args) elif decl_type == "newtype": return symbols.Newtype(decl_name, None, decl_args) else: return symbols.Declaration(line) decls = map(toDecl, contents) for decl in decls: m.add_declaration(decl) return m
def _load_standard_module(self, module_name): if module_name not in autocompletion.std_info: module_contents = call_ghcmod_and_wait(['browse', module_name]).splitlines() with autocompletion.std_info_lock: autocompletion.std_info[module_name] = module_contents
def ghcmod_type(filename, module_name, line, column, cabal = None): """ Uses ghc-mod type to infer type """ return call_ghcmod_and_wait(['type', filename, module_name, str(line), str(column)], filename = filename, cabal = cabal)