def __init__(self, panel, cmdargs, tie_stderr=True, **popen_args): stderr_flag = subprocess.STDOUT if tie_stderr else subprocess.PIPE panel_settings = panel.settings() self.prochelp = ProcHelper.ProcHelper(cmdargs, stderr=stderr_flag, **popen_args) self.panel = panel self.lines = [] self.exit_code = -1 self.stdout_collector = None self.stderr_collector = None self.autoindent = panel_settings.get('auto_indent') self.roflag = self.panel.is_read_only() panel_settings.set('auto_indent', False) panel.set_read_only(False) if self.prochelp.process is not None: lines_lock = threading.RLock() self.stdout_collector = FileObjectCollector("stdout-collector", panel, lines_lock, self.lines, self.prochelp.process.stdout) self.stdout_collector.start() if not tie_stderr: self.stderr_collector = FileObjectCollector("stderr-collector", panel, lines_lock, self.lines, self.prochelp.process.stderr) self.stderr_collector.start() else: self.lines = self.prochelp.process_err self.panel.run_command('insert', {'characters': self.prochelp.process_err}) panel_settings.set('auto_indent', self.autoindent) self.panel.set_read_only(self.roflag)
def exec_with_wrapper(exec_with, install_dir, cmd_list): '''Wrapper function for inserting the execution wrapper, e.g., 'cabal exec' or 'stack exec' :returns: Process object from ProcHelper. ''' proc_args = {} if exec_with is not None: if exec_with == 'cabal': cmd_list = ['cabal', 'exec'] + cmd_list cmd_list.insert(3, '--') elif exec_with == 'stack': cmd_list = ['stack', 'exec'] + cmd_list cmd_list.insert(3, '--') else: errmsg = 'HsDevBackend.exec_with_wrapper: Unknown execution prefix \'{0}\''.format( exec_with) raise RuntimeError(errmsg) if install_dir is not None: proc_args['cwd'] = Utils.normalize_path(install_dir) else: cmd = Which.which(cmd_list[0], ProcHelper.ProcHelper.get_extended_path()) if cmd is not None: cmd_list[0] = cmd Logging.log('HsDevBackend.exec_with_wrapper: {0}'.format(cmd_list), Logging.LOG_DEBUG) return ProcHelper.ProcHelper(cmd_list, **proc_args)
def __init__(self, project, project_dir, opt_args): if debug_any(): print('Starting \'ghc-mod\' for project {0}'.format(project)) self.ghcmod = None self.action_lock = None self.stderr_drain = None self.cmd = [] self.diag_prefix = 'ghc-mod: project ' + project win = sublime.active_window() msg = 'Error and diagnostic output from ' + self.diag_prefix banner = '~' * len(msg) self.output_panel = Common.output_panel( win, panel_name=self.diag_prefix, text='\n'.join([banner, msg, banner, '', ''])) panel_settings = self.output_panel.settings() panel_settings.set("auto_indent", False) panel_settings.set("smart_indent", False) # if self.exec_with is not None: # if self.exec_with == 'cabal': # cmd += ['cabal'] # elif self.exec_with == 'stack': # cmd += ['stack'] self.cmd += ['ghc-mod'] # if self.exec_with is not None: # cmd += ['--'] self.cmd += [ '-b', '\\n', '--line-prefix', self.GHCMOD_OUTPUT_MARKER + ',' + self.GHCMOD_ERROR_MARKER ] self.cmd += opt_args self.cmd += ['legacy-interactive'] if debug_any(): print('ghc-mod command: {0}'.format(self.cmd)) self.ghcmod = ProcHelper.ProcHelper(self.cmd, cwd=project_dir) if self.ghcmod.process is not None: self.ghcmod.process.stdin = io.TextIOWrapper( self.ghcmod.process.stdin, 'utf-8') self.ghcmod.process.stdout = io.TextIOWrapper( self.ghcmod.process.stdout, 'utf-8') self.action_lock = threading.Lock() self.stderr_drain = OutputCollector.DescriptorDrain( self.diag_prefix, self.ghcmod.process.stderr) self.stderr_drain.start() else: Logging.log('Did not start ghc-mod ({0}) successfully.'.format( self.diag_prefix))
def run(self, edit): try: window = self.view.window() window.run_command('hide_panel', { 'panel': 'output.' + SublimeHaskellFilterCommand.OUTPUT_PANEL_NAME }) regions = [] for region in self.view.sel(): regions.append(sublime.Region(region.a, region.b)) if region.empty(): selection = sublime.Region(0, self.view.size()) else: selection = region # Newline conversion seems dubious here, but... leave it alone for the time being. sel_str = self.view.substr(selection).replace('\r\n', '\n') with ProcHelper.ProcHelper(self.indenter) as proc: if proc.process is not None: _, out, err = proc.wait(sel_str) # stylish-haskell does not have a non-zero exit code if it errors out! (Surprise!) # Not sure about hindent, but this seems like a safe enough test. # # Also test if the contents actually changed so break the save-indent-save-indent-... loop if # the user enabled prettify_on_save. # # Yes, I like the explicitness of the 'err' test. It might be slower and less compact that # 'if err and ...', but it does tell one what's going on. if err is None or len(err) == 0: if out not in [selection, sel_str]: self.view.replace(edit, selection, out) else: indent_err = ' '.join(self.indenter) stderr_out = '\n'.join([ "{0} failed, stderr contents:".format( indent_err), "-" * 40, "" ]) + err self.report_error(stderr_out) else: self.report_error(proc.process_err) # Questionable whether regions should be re-activated: stylish-haskell usually adds whitespace, which makes # the selection nonsensical. self.view.sel().clear() for region in regions: self.view.sel().add(region) except OSError: self.report_error('Exception executing {0}'.format(' '.join( self.indenter))) traceback.print_exc()
def do_prettify(view, edit, indenter, indenter_options): try: window = view.window() window.run_command('hide_panel', {'panel': 'output.' + FILTER_OUTPUT_PANEL_NAME}) regions = [] for region in view.sel(): regions.append(sublime.Region(region.a, region.b)) selection = region if not region.empty() else sublime.Region( 0, view.size()) # Newline conversion seems dubious here, but... leave it alone for the time being. sel_str = view.substr(selection).replace('\r\n', '\n') with ProcHelper.ProcHelper(indenter + indenter_options) as proc: if proc.process is not None: _, out, err = proc.wait(sel_str) # stylish-haskell does not have a non-zero exit code if it errors out! (Surprise!) # Not sure about hindent, but this seems like a safe enough test. # # Also test if the contents actually changed so break the save-indent-save-indent-... loop if # the user enabled prettify_on_save. if not err: if out not in [selection, sel_str]: view.replace(edit, selection, out) else: indent_err = ' '.join(indenter) stderr_out = '\n'.join([ "{0} failed, stderr contents:".format(indent_err), "-" * 40, "" ]) + err report_error(view, stderr_out) else: report_error(view, proc.process_err) view.sel().clear() # Questionable whether regions should be re-activated: stylish-haskell usually adds whitespace, which makes # the selection nonsensical. # # However, there are other plugins that get fired after SublimeHaskell that don't like it when you kill all of the # selection regions from underneath their feet. for region in regions: view.sel().add(region) except OSError: report_error(view, 'Exception executing {0}'.format(' '.join(indenter))) traceback.print_exc()
def run(self): cmd = concat_args([(True, ["hsdev", "run"]), (self.port, ["--port", str(self.port)]), (self.cache, ["--cache", self.cache]), (self.log_file, ["--log", self.log_file]), (self.log_config, ["--log-config", self.log_config])]) Logging.log('hsdev command: {0}'.format(cmd), Logging.LOG_DEBUG) while True: self.create_event.wait() self.create_event.clear() while not self.stop_event.is_set(): Logging.log('Starting hsdev server', Logging.LOG_INFO) hsdev_proc = ProcHelper.ProcHelper(cmd) if hsdev_proc.process is None: Logging.log('Failed to create hsdev process', Logging.LOG_ERROR) return None # Use TextIOWrapper here because it combines decoding with newline handling, # which means less to maintain. hsdev_proc.process.stdout = io.TextIOWrapper(hsdev_proc.process.stdout, 'utf-8') hsdev_proc.process.stderr = io.TextIOWrapper(hsdev_proc.process.stderr, 'utf-8') while True: srvout = hsdev_proc.process.stdout.readline().strip() Logging.log('hsdev initial output: {0}'.format(srvout), Logging.LOG_DEBUG) start_confirm = re.match(r'^.*?hsdev> Server started at port (?P<port>\d+)$', srvout) if start_confirm: Logging.log('hsdev server started at port {0}'.format(start_confirm.group('port'))) break self.process = hsdev_proc.process self.drain_stdout = OutputCollector.DescriptorDrain('hsdev stdout', self.process.stdout) self.drain_stderr = OutputCollector.DescriptorDrain('hsdev stderr', self.process.stderr) self.drain_stdout.start() self.drain_stderr.start() HsCallback.call_callback(self.on_start, name='HsDevProcess.on_start') self.process.wait() self.drain_stdout.stop() self.drain_stderr.stop() HsCallback.call_callback(self.on_exit, name='HsDevProcess.on_exit') self.stop_event.clear()
def __init__(self, project, project_dir, opt_args): Logging.log('Starting \'ghc-mod\' for project {0}'.format(project), Logging.LOG_INFO) self.ghcmod = None self.action_lock = None self.stderr_drain = None self.cmd = [] self.diag_prefix = 'ghc-mod ' + project # if self.exec_with is not None: # if self.exec_with == 'cabal': # cmd += ['cabal'] # elif self.exec_with == 'stack': # cmd += ['stack'] self.cmd += ['ghc-mod'] # if self.exec_with is not None: # cmd += ['--'] self.cmd += [ '-b', '\\n', '--line-prefix', self.GHCMOD_OUTPUT_MARKER + ',' + self.GHCMOD_ERROR_MARKER ] self.cmd += opt_args self.cmd += ['legacy-interactive'] Logging.log('ghc-mod command: {0}'.format(self.cmd), Logging.LOG_DEBUG) self.ghcmod = ProcHelper.ProcHelper(self.cmd, cwd=project_dir) if self.ghcmod.process is not None: self.ghcmod.process.stdin = io.TextIOWrapper( self.ghcmod.process.stdin, 'utf-8') self.ghcmod.process.stdout = io.TextIOWrapper( self.ghcmod.process.stdout, 'utf-8') self.action_lock = threading.Lock() self.stderr_drain = OutputCollector.DescriptorDrain( self.diag_prefix, self.ghcmod.process.stderr) self.stderr_drain.start() else: Logging.log('Did not start ghc-mod successfully.')
def admin(cmds, wait=False, **popen_kwargs): if not Settings.PLUGIN.enable_hdevtools: return None hdevtools_socket = Settings.PLUGIN.hdevtools_socket if hdevtools_socket: cmds.append('--socket={0}'.format(hdevtools_socket)) command = ["hdevtools", "admin"] + cmds try: if wait: exit_code, stdout, stderr = ProcHelper.ProcHelper.run_process( command, **popen_kwargs) return stdout if exit_code == 0 else 'error running {0}: {1}'.format( command, stderr) else: proc = ProcHelper.ProcHelper(command, **popen_kwargs) OutputCollector.DescriptorDrain('hdevtools stdout', proc.process.stdout).start() OutputCollector.DescriptorDrain('hdevtools stderr', proc.process.stderr).start() return '' except OSError as os_exc: if os_exc.errno == errno.ENOENT: show_hdevtools_error_and_disable() Settings.PLUGIN.enable_hdevtools = False return None except Exception: Logging.log( 'hdevtools.admin failed with exception, see console window traceback' ) traceback.print_exc() return None
def run(self): new_simple_log = patch_simple_log(self.version) cmd = concat_args([ (True, ["hsdev", "run"]), (self.port, ["--port", str(self.port)]), (self.cache, ["--cache", self.cache]), (self.log_file, ["--log", self.log_file]), # HACK! HACK! HACK! Alexandr changed simple-log's command line API. # # "--log-config" only applies to earlier hsdev versions that support 'log politics' (and for those # of us old enough to remember the Soviet era, 'log politics' is an incredibly Soviet notion that # makes us smile! :-) # # Versions 0.2.3.0 and later: Simplified argument -- just the log level, and only one log level, # Yvgeny! (With apologies to "The Hunt for Red October".) (not new_simple_log and self.log_config, ["--log-config", self.log_config]), (new_simple_log and self.log_config, ["--log-level", self.log_config]) ]) Logging.log('hsdev command: {0}'.format(cmd), Logging.LOG_DEBUG) while True: self.create_event.wait() self.create_event.clear() while not self.stop_event.is_set(): Logging.log('Starting hsdev server', Logging.LOG_INFO) hsdev_proc = ProcHelper.ProcHelper(cmd) if hsdev_proc.process is None: Logging.log('Failed to create hsdev process', Logging.LOG_ERROR) return # Use TextIOWrapper here because it combines decoding with newline handling, # which means less to maintain. hsdev_proc.process.stdout = io.TextIOWrapper( hsdev_proc.process.stdout, 'utf-8') hsdev_proc.process.stderr = io.TextIOWrapper( hsdev_proc.process.stderr, 'utf-8') while True: srvout = hsdev_proc.process.stdout.readline().strip() if srvout != '': Logging.log('hsdev initial output: {0}'.format(srvout), Logging.LOG_DEBUG) start_confirm = re.search( r'[Ss]erver started at port (?P<port>\d+)$', srvout) if start_confirm: Logging.log( 'hsdev server started at port {0}'.format( start_confirm.group('port'))) break else: Logging.log( 'hsdev initial output: Got EOF. Server not started successfully.' ) return self.process = hsdev_proc.process self.drain_stdout = OutputCollector.DescriptorDrain( 'hsdev stdout', self.process.stdout) self.drain_stderr = OutputCollector.DescriptorDrain( 'hsdev stderr', self.process.stderr) self.drain_stdout.start() self.drain_stderr.start() HsCallback.call_callback(self.on_start, name='HsDevProcess.on_start') self.process.wait() self.drain_stdout.stop() self.drain_stderr.stop() HsCallback.call_callback(self.on_exit, name='HsDevProcess.on_exit') self.stop_event.clear()