Shopify / Shopify/shadowenv

Editor/IDE integrations

Open
#22 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
458
Forks
22
PR merge metrics
No merged PRs in 30d

Description

  • vim
  • emacs
  • vscode
  • sublime?
  • atom?
  • RubyMine / jetbrains family? Possibly via EnvFile
  • ...

This should, in principle, be pretty easy to build in each case as long as we can:

  • Run some code when we "change directory" or open a file;
  • Shell out and get the output back; and
  • Mutate the process environment.

direnv.vim is probably close to a solution but has no license. Direnv is MIT-licensed so we could just confirm that if it would be useful to start from there.

Some code we wrote to do this in a private repo follows, may be a helpful reference:

# frozen_string_literal: true

require('dev')

module Dev
  class Shadowenv
    module Applicator
      extend Dev::Util::PrivateConstants

      private_constants do
        ASCII_FIELD_SEPARATOR  = "\x1F"
        ASCII_RECORD_SEPARATOR = "\x1E"
        OPCODE_SET_UNEXPORTED  = 1
        OPCODE_SET_EXPORTED    = 2
        OPCODE_UNSET           = 3
      end

      class << self
        # applies a shadowenv found by the normal rules (recursing upward to
        # parents until one contains a `.shadowenv.d`) to the provided
        # `Dev::Context`'s `env`.
        def apply(ctx, dir)
          Dev::Shadowenv::Installer.ensure_installed

          data = ctx.shadowenv_data || ''
          out, err, stat = ctx.capture3('shadowenv', 'hook', '--porcelain', data, chdir: dir)
          raise(Dev::Bug, "shadowenv failed: #{err}") unless stat.success?

          # Fields separated by 0x1F; records separated by 0x1E.
          # example message:
          #   0x02 0x1F F O O 0x1F b a r 0x1E
          #   ^         ^          ^
          #   export    FOO=       bar
          out.split(ASCII_RECORD_SEPARATOR).each do |record|
            opcode, name, value = record.split(ASCII_FIELD_SEPARATOR)
            case opcode.bytes.first
            when OPCODE_SET_EXPORTED
              ctx.env[name] = value
            when OPCODE_UNSET
              ctx.env[name] = nil
            when OPCODE_SET_UNEXPORTED
              # __shadowenv_data specifically is set, but not exported to
              # subprocesses. It lives only in the shell session itself as an
              # unexported variable.
              if name == '__shadowenv_data'
                ctx.shadowenv_data = value
              else
                raise(
                  Dev::Bug,
                  "shadowenv gave us an unexported value that we didn't know what to do with: #{name}",
                )
              end
            end
          end
          nil
        end
      end
    end
  end
end

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue lists existing vim and emacs integrations plus unchecked targets such as vscode, and includes links to shadowenv.vim and shadowenv.el. Start by choosing one unchecked editor and reviewing the listed integration requirements; done would mean that editor can react to directory or file changes, invoke shadowenv, and update its process environment.

Written by the indexing model from the issue text.

Assessment

Tech stack
emacs, vim, vscode
Domain
developer-experience, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.