Sublime Forum

Request: Show Build Results on Right

#1

Would it be possible to add a feature which allows the build output of my code to be shown on the right side (or other custom locations) on the sublime interface? This would significantly improve my ability to look between code and results.
(If this can’t be done, are there reasons that this isn’t already a feature? What impedes this being enabled?)
Thanks in advance.

2 Likes

#2

You can achieve something like this using inline error messages, or if that isn’t suitable you can split the window vertically and run the Terminus plugin in the right pane doing the build.

0 Likes

#3

I wrote a build system script that pretty much accomplishes what you want. Currently it’s adapted for C and C++ compilers, but you could customize it for your own compiler.

It creates a log file in the temporary directory of your system and directs stdout and stderr of the compiling process to that log file. If something went wrong during compilation, it opens the log file in Sublime Text (or updates it if it’s already open). You can then move that log file’s tab to a separate column in Sublime Text (View -> Layout).

Put the following two files in your data/packages/user directory and change the build system to your preference.

gnu_build.py

import sublime
import sublime_plugin

import tempfile
import subprocess
import os
import threading

class GnuBuildThread(threading.Thread):
  func_compile = None
  func_run = None
  args_compile = ()
  args_run = ()

  def __init__(self, func_compile, func_run, args_compile, args_run):
    threading.Thread.__init__(self)
    self.func_compile = func_compile
    self.func_run = func_run
    self.args_compile = args_compile
    self.args_run = args_run

  def run(self):
    compile_result = self.func_compile(*self.args_compile)
    self.func_run(compile_result, *self.args_run)

class GnuBuildCommand(sublime_plugin.WindowCommand):

  variables = {}
  proc = None
  log = False
  log_path = ""
  log_name = ""

  def compile_file(self, compiler, compiler_args):
    if self.proc is not None:
      self.proc.terminate()
      self.proc = None

    if self.log:
      self.log_path = tempfile.gettempdir() + '/' + self.log_name
      log_file = open(self.log_path, 'w')
    else:
      log_file = None

    working_dir = self.variables['file_path']
    executable_name = self.variables['file_base_name']

    si = None
    # if Windows, dont show terminal when compiling
    if os.name == 'nt':
      si = subprocess.STARTUPINFO()
      si.dwFlags = subprocess.STARTF_USESHOWWINDOW
      si.wShowWindow = 0

    # compile and build
    build_args = [compiler]
    build_args.append(self.variables['file_name'])
    if len(compiler_args) > 0:
      build_args.extend(compiler_args)
    build_args.append('-o')
    build_args.append(executable_name)

    self.proc = subprocess.Popen(
        build_args,
        stdout=log_file if self.log else None,
        stderr=subprocess.STDOUT if self.log else None,
        cwd=working_dir,
        startupinfo=si
    )
    result = self.proc.wait()

    if self.log:
      log_file.close()

    return result


  def program_run(self, compile_result, success_cmd):
    working_dir = self.variables['file_path']

    if compile_result == 0:
      if len(success_cmd) > 0:
        for i in range(0, len(success_cmd)):
          success_cmd[i] = sublime.expand_variables(success_cmd[i], self.variables)

        subprocess.Popen(
            success_cmd,
            cwd=working_dir
        )
    elif self.log:
      active_view = self.window.active_view()
      self.window.open_file(self.log_path)
      self.window.focus_view(active_view)

  def run(self, compiler, compiler_args=[], success_cmd=[],
          log=False, log_name="errors.log", kill=False):
    if len(compiler) < 1:
      raise Exception('"compiler" argument empty')

    if kill:
      if self.proc:
        self.proc.terminate()
      return

    self.variables = self.window.extract_variables()
    self.log = log
    self.log_name = log_name

    GnuBuildThread(
      func_compile=self.compile_file,
      args_compile=(compiler, compiler_args,),
      func_run=self.program_run,
      args_run=(success_cmd,)
    ).start()

  def is_enabled(self, compiler, compiler_args=[], success_cmd=[],
          log=False, log_name="errors.log", kill=False):
    if kill:
      return self.proc is not None and self.proc.poll() is None
    return True

gnu_build.sublime-build

{
  "target": "gnu_build",
  "cancel": { "kill": true },
  "compiler": "clang++",
  "compiler_args": [
    "-Wno-deprecated-declarations"
  ],
  "log_name": "errors.log",
  "selector": "source.c++",
  "variants": [
    {
      "name": "Run",
      "success_cmd": ["./$file_base_name"]
    },
    {
      "name": "Log",
      "log": true
    },
    {
      "name": "Log & Run",
      "log": true,
      "success_cmd": ["./$file_base_name"]
    }
  ]
}
0 Likes

#4

Of course, this is just a workaround. It could be extended to use fields like file_regex

0 Likes

#5

I think this request is still valuable in a more generalized implementation.

I’ve long wanted vertical build results, and recently have been using LSP over plain linters, and I’d like to be able to set the messaging and warnings off to the side where it won’t be reducing my code’s vertical visibility. As I understand LSP uses a view separate than the “build results” view, but generalizing the feature for both would be amazing.

Widescreen, especially ultra wide displays are just silly with the build results spanning the entire lower edge of the project window, especially when results are wrapped less than the window width.

Having to set build systems for every permutation is a little tiring.

0 Likes

#6

There is an open feature request for this.

1 Like