Pragmatism in today's world

Opening Sublime Text from the command line

I nearly always open Sublime Text from the command line using subl and have specific requirements for when it should open a new window or re-use one.

If I’m opening a directory, then I would like it to re-use the same window if I have previously opened that directory. However if I open a random file, I never want that file in the last directory window as it’s unrelated.

To do this I wrote a simple bash function:

# subl: wrapper that opens files in a new window, and reuses the window
# for directories
subl() {
  local args=() opts=()
  for a in "$@"; do
    if [[ "$a" == -* ]]; then
      opts+=("$a")
    else
      args+=("$a")
    fi
  done
  # No path argument means the current directory
  [[ ${#args[@]} -eq 0 ]] && args=(.)

  if [[ ${#args[@]} -eq 1 && -d "${args[0]}" ]]; then
    # Single directory: open in same window
    command subl "${opts[@]}" "${args[0]}"
  else
    # File(s): so open in a new window
    command subl -n "${opts[@]}" "${args[@]}"
  fi
}

Firstly we determine which parameters on the command line are arguments and which are options. Options start with a dash and arguments are either file or directory names.

After that, we inspect the arguments.

  • If there’s no arguments, or if there’s one argument that is a directory, then we open Sublime Text with the arguments and options we collected and a new directory window opens, unless the directory is already open, in which case it is reused.
  • Otherwise we open Sublime Text with the -n option in addition to those passed in. This has the effect of forcing a new window to open.

Remembering which files were last open

This works really well, but if I close a directory window and then open it again, it has forgotten which files I had open. To get Sublime Text to remember, we need a project file. This is a JSON file with the extension .sublime-project file and a minimal one would be:

{
    "folders": [
        {
            "path": "."
        }
    ]
}

We then open a directory with subl foo.sublime-project and then the open files are persisted across sessions.

Obviously, I’m not going to manually create this file or remember to use it as argument, so I extended my subl() function to manage the project file for me:

# subl: wrapper that opens files in a new window, and directories in the same
# window as a Sublime project, reusing an existing .sublime-project, creating
# one if opening a dir.
subl() {
  local args=() opts=()
  for a in "$@"; do
    if [[ "$a" == -* ]]; then
      opts+=("$a")
    else
      args+=("$a")
    fi
  done
  # No path argument means the current directory
  [[ ${#args[@]} -eq 0 ]] && args=(.)
  if [[ ${#args[@]} -eq 1 && -d "${args[0]}" ]]; then
    # Single directory: use existing project or create one, then open in same window
    local proj
    proj=$(find "${args[0]}" -maxdepth 1 -name '*.sublime-project' -print -quit)
    if [[ -z "$proj" ]]; then
      local name
      name=$(basename "$(cd "${args[0]}" && pwd)")
      proj="${args[0]}/${name}.sublime-project"
      cat > "$proj" <

The comment covers what happens. Firstly we check for a sublime-project file. If one doesn't exist, then we create a default one called {directory name}.sublime-project. I'm not particularly interested in this project file, so I exclude it from the Sublime Text side bar using the file_exclude_patterns option within the project file itself. Then we open the project with the options that were provided on the command line.

Now subl . in a fresh directory creates a hidden project file and opens it, and every subl after that picks the project back up with my files open exactly where I left them.

Thoughts? Leave a reply

Your email address will not be published. Required fields are marked *