Class: Pikuri::Lsp::Registry::StdioEntry

Inherits:
Data
  • Object
show all
Defined in:
lib/pikuri/lsp/registry.rb

Overview

One language server: the argv to launch it and the files it answers for.

files holds basename globs, not extensions, because Rakefile has none — and it is the dispatch key, so getting it wrong sends Ruby questions to a Java server rather than merely failing.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil) ⇒ StdioEntry

Returns a new instance of StdioEntry.

Raises:

  • (ArgumentError)

    on an empty id / command / files, or when language_id: is omitted and no glob in files carries an extension LANGUAGE_IDS knows.



88
89
90
91
92
93
94
95
96
# File 'lib/pikuri/lsp/registry.rb', line 88

def initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil)
  raise ArgumentError, "id must be a non-empty String, got #{id.inspect}" if id.to_s.empty?
  raise ArgumentError, "command must be a non-empty argv Array, got #{command.inspect}" if command.to_a.empty?
  raise ArgumentError, "files must be a non-empty glob Array, got #{files.inspect}" if files.to_a.empty?

  super(id: id, command: command.freeze, files: files.freeze,
        language_id: language_id || Registry.derive_language_id(files, id),
        env: env.freeze, init_options: init_options)
end

Instance Attribute Details

#commandArray<String> (readonly)

Returns argv, e.g. ["jdtls", "-data", "/…/cache"]. Spawned with cwd = the workspace root, always.

Returns:

  • (Array<String>)

    argv, e.g. ["jdtls", "-data", "/…/cache"]. Spawned with cwd = the workspace root, always.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/pikuri/lsp/registry.rb', line 84

StdioEntry = Data.define(:id, :command, :files, :language_id, :env, :init_options) do
  # @raise [ArgumentError] on an empty +id+ / +command+ / +files+, or when
  #   +language_id:+ is omitted and no glob in +files+ carries an
  #   extension {LANGUAGE_IDS} knows.
  def initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil)
    raise ArgumentError, "id must be a non-empty String, got #{id.inspect}" if id.to_s.empty?
    raise ArgumentError, "command must be a non-empty argv Array, got #{command.inspect}" if command.to_a.empty?
    raise ArgumentError, "files must be a non-empty glob Array, got #{files.inspect}" if files.to_a.empty?

    super(id: id, command: command.freeze, files: files.freeze,
          language_id: language_id || Registry.derive_language_id(files, id),
          env: env.freeze, init_options: init_options)
  end

  # Whether this server answers for +path+ — matched on the basename, so a
  # directory component never decides which server sees a file.
  #
  # @param path [String, Pathname] absolute or relative; only the basename
  #   is read.
  # @return [Boolean]
  def claims?(path)
    basename = File.basename(path.to_s)
    files.any? { |glob| File.fnmatch?(glob, basename, File::FNM_DOTMATCH) }
  end
end

#envHash{String => String} (readonly)

Returns extra environment for the child, merged over the de-bundlerized environment (BundlerEnv), e.g. {"JAVA_HOME" => "/usr/lib/jvm/java-21"}. Frozen, defaults to {}. The legitimate per-child credential channel of the "environment is not a secret store" seam.

Returns:

  • (Hash{String => String})

    extra environment for the child, merged over the de-bundlerized environment (BundlerEnv), e.g. {"JAVA_HOME" => "/usr/lib/jvm/java-21"}. Frozen, defaults to {}. The legitimate per-child credential channel of the "environment is not a secret store" seam.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/pikuri/lsp/registry.rb', line 84

StdioEntry = Data.define(:id, :command, :files, :language_id, :env, :init_options) do
  # @raise [ArgumentError] on an empty +id+ / +command+ / +files+, or when
  #   +language_id:+ is omitted and no glob in +files+ carries an
  #   extension {LANGUAGE_IDS} knows.
  def initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil)
    raise ArgumentError, "id must be a non-empty String, got #{id.inspect}" if id.to_s.empty?
    raise ArgumentError, "command must be a non-empty argv Array, got #{command.inspect}" if command.to_a.empty?
    raise ArgumentError, "files must be a non-empty glob Array, got #{files.inspect}" if files.to_a.empty?

    super(id: id, command: command.freeze, files: files.freeze,
          language_id: language_id || Registry.derive_language_id(files, id),
          env: env.freeze, init_options: init_options)
  end

  # Whether this server answers for +path+ — matched on the basename, so a
  # directory component never decides which server sees a file.
  #
  # @param path [String, Pathname] absolute or relative; only the basename
  #   is read.
  # @return [Boolean]
  def claims?(path)
    basename = File.basename(path.to_s)
    files.any? { |glob| File.fnmatch?(glob, basename, File::FNM_DOTMATCH) }
  end
end

#filesArray<String> (readonly)

Returns basename globs, e.g. ["*.rb", "*.rake", "Rakefile"]. First entry whose glob matches wins; overlaps are not detected.

Returns:

  • (Array<String>)

    basename globs, e.g. ["*.rb", "*.rake", "Rakefile"]. First entry whose glob matches wins; overlaps are not detected.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/pikuri/lsp/registry.rb', line 84

StdioEntry = Data.define(:id, :command, :files, :language_id, :env, :init_options) do
  # @raise [ArgumentError] on an empty +id+ / +command+ / +files+, or when
  #   +language_id:+ is omitted and no glob in +files+ carries an
  #   extension {LANGUAGE_IDS} knows.
  def initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil)
    raise ArgumentError, "id must be a non-empty String, got #{id.inspect}" if id.to_s.empty?
    raise ArgumentError, "command must be a non-empty argv Array, got #{command.inspect}" if command.to_a.empty?
    raise ArgumentError, "files must be a non-empty glob Array, got #{files.inspect}" if files.to_a.empty?

    super(id: id, command: command.freeze, files: files.freeze,
          language_id: language_id || Registry.derive_language_id(files, id),
          env: env.freeze, init_options: init_options)
  end

  # Whether this server answers for +path+ — matched on the basename, so a
  # directory component never decides which server sees a file.
  #
  # @param path [String, Pathname] absolute or relative; only the basename
  #   is read.
  # @return [Boolean]
  def claims?(path)
    basename = File.basename(path.to_s)
    files.any? { |glob| File.fnmatch?(glob, basename, File::FNM_DOTMATCH) }
  end
end

#idString (readonly)

Returns this server's name in log lines, restart messages and ServerProgress#server_id, e.g. "ruby". Never model-facing: the model names no server, it names a file.

Returns:

  • (String)

    this server's name in log lines, restart messages and ServerProgress#server_id, e.g. "ruby". Never model-facing: the model names no server, it names a file.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/pikuri/lsp/registry.rb', line 84

StdioEntry = Data.define(:id, :command, :files, :language_id, :env, :init_options) do
  # @raise [ArgumentError] on an empty +id+ / +command+ / +files+, or when
  #   +language_id:+ is omitted and no glob in +files+ carries an
  #   extension {LANGUAGE_IDS} knows.
  def initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil)
    raise ArgumentError, "id must be a non-empty String, got #{id.inspect}" if id.to_s.empty?
    raise ArgumentError, "command must be a non-empty argv Array, got #{command.inspect}" if command.to_a.empty?
    raise ArgumentError, "files must be a non-empty glob Array, got #{files.inspect}" if files.to_a.empty?

    super(id: id, command: command.freeze, files: files.freeze,
          language_id: language_id || Registry.derive_language_id(files, id),
          env: env.freeze, init_options: init_options)
  end

  # Whether this server answers for +path+ — matched on the basename, so a
  # directory component never decides which server sees a file.
  #
  # @param path [String, Pathname] absolute or relative; only the basename
  #   is read.
  # @return [Boolean]
  def claims?(path)
    basename = File.basename(path.to_s)
    files.any? { |glob| File.fnmatch?(glob, basename, File::FNM_DOTMATCH) }
  end
end

#init_optionsHash? (readonly)

Returns initializationOptions, passed verbatim at handshake time and never parsed by pikuri — the home for outbound per-server glue, e.g. jdtls's classFileContentsSupport, without which every library symbol answers with silence. There is deliberately no sibling settings: field for answering the server's workspace/configuration requests: Connection replies null to every server-initiated request, and both reference servers tolerate that.

Returns:

  • (Hash, nil)

    initializationOptions, passed verbatim at handshake time and never parsed by pikuri — the home for outbound per-server glue, e.g. jdtls's classFileContentsSupport, without which every library symbol answers with silence. There is deliberately no sibling settings: field for answering the server's workspace/configuration requests: Connection replies null to every server-initiated request, and both reference servers tolerate that.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/pikuri/lsp/registry.rb', line 84

StdioEntry = Data.define(:id, :command, :files, :language_id, :env, :init_options) do
  # @raise [ArgumentError] on an empty +id+ / +command+ / +files+, or when
  #   +language_id:+ is omitted and no glob in +files+ carries an
  #   extension {LANGUAGE_IDS} knows.
  def initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil)
    raise ArgumentError, "id must be a non-empty String, got #{id.inspect}" if id.to_s.empty?
    raise ArgumentError, "command must be a non-empty argv Array, got #{command.inspect}" if command.to_a.empty?
    raise ArgumentError, "files must be a non-empty glob Array, got #{files.inspect}" if files.to_a.empty?

    super(id: id, command: command.freeze, files: files.freeze,
          language_id: language_id || Registry.derive_language_id(files, id),
          env: env.freeze, init_options: init_options)
  end

  # Whether this server answers for +path+ — matched on the basename, so a
  # directory component never decides which server sees a file.
  #
  # @param path [String, Pathname] absolute or relative; only the basename
  #   is read.
  # @return [Boolean]
  def claims?(path)
    basename = File.basename(path.to_s)
    files.any? { |glob| File.fnmatch?(glob, basename, File::FNM_DOTMATCH) }
  end
end

#language_idString (readonly)

Returns the languageId every didOpen carries, e.g. "ruby". Derived at construction from the first extension-bearing glob when not given — per entry, not per file, which is wrong for the +eslint+-shaped server that claims eight extensions and right for everything pikuri has met.

Returns:

  • (String)

    the languageId every didOpen carries, e.g. "ruby". Derived at construction from the first extension-bearing glob when not given — per entry, not per file, which is wrong for the +eslint+-shaped server that claims eight extensions and right for everything pikuri has met.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/pikuri/lsp/registry.rb', line 84

StdioEntry = Data.define(:id, :command, :files, :language_id, :env, :init_options) do
  # @raise [ArgumentError] on an empty +id+ / +command+ / +files+, or when
  #   +language_id:+ is omitted and no glob in +files+ carries an
  #   extension {LANGUAGE_IDS} knows.
  def initialize(id:, command:, files:, language_id: nil, env: {}, init_options: nil)
    raise ArgumentError, "id must be a non-empty String, got #{id.inspect}" if id.to_s.empty?
    raise ArgumentError, "command must be a non-empty argv Array, got #{command.inspect}" if command.to_a.empty?
    raise ArgumentError, "files must be a non-empty glob Array, got #{files.inspect}" if files.to_a.empty?

    super(id: id, command: command.freeze, files: files.freeze,
          language_id: language_id || Registry.derive_language_id(files, id),
          env: env.freeze, init_options: init_options)
  end

  # Whether this server answers for +path+ — matched on the basename, so a
  # directory component never decides which server sees a file.
  #
  # @param path [String, Pathname] absolute or relative; only the basename
  #   is read.
  # @return [Boolean]
  def claims?(path)
    basename = File.basename(path.to_s)
    files.any? { |glob| File.fnmatch?(glob, basename, File::FNM_DOTMATCH) }
  end
end

Instance Method Details

#claims?(path) ⇒ Boolean

Whether this server answers for path — matched on the basename, so a directory component never decides which server sees a file.

Parameters:

  • path (String, Pathname)

    absolute or relative; only the basename is read.

Returns:

  • (Boolean)


104
105
106
107
# File 'lib/pikuri/lsp/registry.rb', line 104

def claims?(path)
  basename = File.basename(path.to_s)
  files.any? { |glob| File.fnmatch?(glob, basename, File::FNM_DOTMATCH) }
end