Module: RuVim::Browser

Defined in:
lib/ruvim/browser.rb

Constant Summary collapse

ALLOWED_SCHEMES =
%w[https http].freeze

Class Method Summary collapse

Class Method Details

.command_available?(name) ⇒ Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/ruvim/browser.rb', line 100

def command_available?(name)
  system("which", name, out: File::NULL, err: File::NULL)
end

.detect_backendObject



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/ruvim/browser.rb', line 41

def detect_backend
  return { command: %w[open], type: :macos } if command_available?("open") && macos?
  return { command: %w[xdg-open], type: :xdg } if command_available?("xdg-open") && !wsl?
  return { command: %w[wslview], type: :wslview } if command_available?("wslview")

  ps_path = powershell_path(wsl_mount_point)
  if wsl? && File.exist?(ps_path)
    return { ps_path: ps_path, type: :powershell }
  end

  nil
end

.macos?Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/ruvim/browser.rb', line 82

def macos?
  RUBY_PLATFORM.include?("darwin")
end

.open_url(url) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/ruvim/browser.rb', line 11

def open_url(url)
  return false unless valid_url?(url)

  backend = detect_backend
  return false unless backend

  if backend[:type] == :powershell
    cmd = powershell_encoded_command(backend[:ps_path], url)
    _, _, status = Open3.capture3(*cmd)
  else
    _, _, status = Open3.capture3(*backend[:command], url)
  end
  status.success?
rescue StandardError
  false
end

.powershell_encoded_command(ps_path, url) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/ruvim/browser.rb', line 33

def powershell_encoded_command(ps_path, url)
  # Encode as UTF-16LE Base64 to avoid any command injection via -Command.
  # This matches the approach used by Node.js "open" package.
  ps_script = "Start-Process '#{url.gsub("'", "''")}'"
  encoded = [ps_script.encode("UTF-16LE")].pack("m0")
  [ps_path, "-NoProfile", "-NonInteractive", "-EncodedCommand", encoded]
end

.powershell_path(mount_point) ⇒ Object



54
55
56
# File 'lib/ruvim/browser.rb', line 54

def powershell_path(mount_point)
  "#{mount_point}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe"
end

.reset!Object



96
97
98
# File 'lib/ruvim/browser.rb', line 96

def reset!
  @wsl = nil
end

.valid_url?(url) ⇒ Boolean

Returns:

  • (Boolean)


28
29
30
31
# File 'lib/ruvim/browser.rb', line 28

def valid_url?(url)
  scheme = url.to_s.split(":", 2).first.to_s.downcase
  ALLOWED_SCHEMES.include?(scheme)
end

.wsl?Boolean

Returns:

  • (Boolean)


86
87
88
89
90
91
92
93
94
# File 'lib/ruvim/browser.rb', line 86

def wsl?
  return @wsl if defined?(@wsl)

  @wsl = begin
    File.read("/proc/version").include?("microsoft")
  rescue StandardError
    false
  end
end

.wsl_mount_point(config: nil) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ruvim/browser.rb', line 58

def wsl_mount_point(config: nil)
  config ||= begin
    File.read("/etc/wsl.conf")
  rescue StandardError
    nil
  end

  default = "/mnt/"
  return default unless config

  config.each_line do |line|
    stripped = line.strip
    next if stripped.start_with?("#")

    if stripped.match?(/\Aroot\s*=/)
      value = stripped.sub(/\Aroot\s*=\s*/, "").strip
      value += "/" unless value.end_with?("/")
      return value
    end
  end

  default
end