Class: PuppetLanguageServer::SessionState::LanguageClient

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet-languageserver/session_state/language_client.rb

Constant Summary collapse

DEFAULT_FORMAT_ON_TYPE_ENABLE =
false
DEFAULT_FORMAT_ON_TYPE_FILESIZE_LIMIT =
4096
DEFAULT_FOLDING_RANGE_ENABLE =

Default is true as per VS Code

true
DEFAULT_FOLDING_RANGE_SHOW_LAST_LINE =

Default is true as per VS Code

true
DEFAULT_VALIDATE_RESOLVE_PUPPETFILES =
true

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(message_handler) ⇒ LanguageClient

Returns a new instance of LanguageClient.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 17

def initialize(message_handler)
  @message_handler = message_handler
  @client_capabilites = {}

  # Internal registry of dynamic registrations and their current state
  # @registrations[ <[String] method_name>] = [
  #  {
  #    :id         => [String] Request ID. Used for de-registration
  #    :registered => [Boolean] true | false
  #    :state      => [Enum] :pending | :complete
  #   }
  # ]
  @registrations = {}

  # Initial state. Not always the same as defaults
  @folding_range = false
  @folding_range_show_last_line = DEFAULT_FOLDING_RANGE_SHOW_LAST_LINE
  @format_on_type = false
  @format_on_type_filesize_limit = DEFAULT_FORMAT_ON_TYPE_FILESIZE_LIMIT
  @use_puppetfile_resolver = DEFAULT_VALIDATE_RESOLVE_PUPPETFILES
end

Instance Attribute Details

#folding_rangeObject (readonly)

Returns the value of attribute folding_range.



6
7
8
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 6

def folding_range
  @folding_range
end

#folding_range_show_last_lineObject (readonly)

Returns the value of attribute folding_range_show_last_line.



6
7
8
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 6

def folding_range_show_last_line
  @folding_range_show_last_line
end

#format_on_typeObject (readonly)

Client settings



9
10
11
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 9

def format_on_type
  @format_on_type
end

#format_on_type_filesize_limitObject (readonly)

Returns the value of attribute format_on_type_filesize_limit.



6
7
8
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 6

def format_on_type_filesize_limit
  @format_on_type_filesize_limit
end

#message_handlerObject (readonly)

Returns the value of attribute message_handler.



6
7
8
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 6

def message_handler
  @message_handler
end

#use_puppetfile_resolverObject (readonly)

Returns the value of attribute use_puppetfile_resolver.



6
7
8
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 6

def use_puppetfile_resolver
  @use_puppetfile_resolver
end

Instance Method Details

#capability_registrations(method) ⇒ Object



92
93
94
95
96
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 92

def capability_registrations(method)
  return [{ registered: false, state: :complete }] if @registrations[method].nil? || @registrations[method].empty?

  @registrations[method].dup
end

#client_capability(*names) ⇒ Object



39
40
41
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 39

def client_capability(*names)
  safe_hash_traverse(@client_capabilites, *names)
end

#parse_lsp_configuration_settings!(settings = {}) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 55

def parse_lsp_configuration_settings!(settings = {})
  # format on type enabled
  value = to_boolean(safe_hash_traverse(settings, 'puppet', 'editorService', 'formatOnType', 'enable'), DEFAULT_FORMAT_ON_TYPE_ENABLE)
  unless value == @format_on_type # Ummm no.
    # Is dynamic registration available?
    if client_capability('textDocument', 'onTypeFormatting', 'dynamicRegistration') == true
      if value
        register_capability('textDocument/onTypeFormatting', PuppetLanguageServer::ServerCapabilites.document_on_type_formatting_options)
      else
        unregister_capability('textDocument/onTypeFormatting')
      end
    end
    @format_on_type = value
  end
  # format on type file size
  @format_on_type_filesize_limit = to_integer(safe_hash_traverse(settings, 'puppet', 'editorService', 'formatOnType', 'maxFileSize'), DEFAULT_FORMAT_ON_TYPE_FILESIZE_LIMIT, 0)

  # use puppetfile resolver
  @use_puppetfile_resolver = to_boolean(safe_hash_traverse(settings, 'puppet', 'validate', 'resolvePuppetfiles'), DEFAULT_VALIDATE_RESOLVE_PUPPETFILES)

  # folding range enabled
  value = to_boolean(safe_hash_traverse(settings, 'puppet', 'editorService', 'foldingRange', 'enable'), DEFAULT_FOLDING_RANGE_ENABLE) && PuppetLanguageServer::ServerCapabilites.folding_provider_supported?
  unless value == @folding_range # Ummm no.
    # Is dynamic registration available?
    if client_capability('textDocument', 'foldingRange', 'dynamicRegistration') == true
      if value
        register_capability('textDocument/foldingRange', PuppetLanguageServer::ServerCapabilites.document_on_type_formatting_options)
      else
        unregister_capability('textDocument/foldingRange')
      end
    end
    @folding_range = value
  end
  # folding range last line display
  @folding_range_show_last_line = to_boolean(safe_hash_traverse(settings, 'puppet', 'editorService', 'foldingRange', 'showLastLine'), DEFAULT_FOLDING_RANGE_SHOW_LAST_LINE)
end

#parse_lsp_initialize!(initialize_params = {}) ⇒ Object



51
52
53
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 51

def parse_lsp_initialize!(initialize_params = {})
  @client_capabilites = initialize_params['capabilities']
end

#parse_register_capability_response!(response, original_request) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 147

def parse_register_capability_response!(response, original_request)
  raise 'Response is not from client/registerCapability request' unless original_request.rpc_method == 'client/registerCapability'

  unless response.is_successful
    original_request.params.registrations.each do |reg|
      # Mark the registration as completed and failed
      @registrations[reg.method__lsp] = [] if @registrations[reg.method__lsp].nil?
      @registrations[reg.method__lsp].select { |i| i[:id] == reg.id }.each { |i| i[:registered] = false; i[:state] = :complete } # rubocop:disable Style/Semicolon This is fine
    end
    return true
  end

  original_request.params.registrations.each do |reg|
    PuppetLanguageServer.log_message(:info, "Succesfully dynamically registered the #{reg.method__lsp} method")

    # Mark the registration as completed and succesful
    @registrations[reg.method__lsp] = [] if @registrations[reg.method__lsp].nil?
    @registrations[reg.method__lsp].select { |i| i[:id] == reg.id }.each { |i| i[:registered] = true; i[:state] = :complete } # rubocop:disable Style/Semicolon This is fine

    # If we just registered the workspace/didChangeConfiguration method then
    # also trigger a configuration request to get the initial state
    send_configuration_request if reg.method__lsp == 'workspace/didChangeConfiguration'
  end

  true
end

#parse_unregister_capability_response!(response, original_request) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 174

def parse_unregister_capability_response!(response, original_request)
  raise 'Response is not from client/unregisterCapability request' unless original_request.rpc_method == 'client/unregisterCapability'

  unless response.is_successful
    original_request.params.unregisterations.each do |reg|
      # Mark the registration as completed and failed
      @registrations[reg.method__lsp] = [] if @registrations[reg.method__lsp].nil?
      @registrations[reg.method__lsp].select { |i| i[:id] == reg.id && i[:registered] }.each { |i| i[:state] = :complete }
      @registrations[reg.method__lsp].delete_if { |i| i[:id] == reg.id && !i[:registered] }
    end
    return true
  end

  original_request.params.unregisterations.each do |reg|
    PuppetLanguageServer.log_message(:info, "Succesfully dynamically unregistered the #{reg.method__lsp} method")

    # Remove registrations
    @registrations[reg.method__lsp] = [] if @registrations[reg.method__lsp].nil?
    @registrations[reg.method__lsp].delete_if { |i| i[:id] == reg.id }
  end

  true
end

#register_capability(method, options = {}) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 98

def register_capability(method, options = {})
  id = new_request_id

  PuppetLanguageServer.log_message(:info, "Attempting to dynamically register the #{method} method with id #{id}")

  if @registrations[method] && @registrations[method].select { |i| i[:state] == :pending }.count > 0
    # The protocol doesn't specify whether this is allowed and is probably per client specific. For the moment we will allow
    # the registration to be sent but log a message that something may be wrong.
    PuppetLanguageServer.log_message(:warn, "A dynamic registration/deregistration for the #{method} method is already in progress")
  end

  params = LSP::RegistrationParams.new.from_h!('registrations' => [])
  params.registrations << LSP::Registration.new.from_h!('id' => id, 'method' => method, 'registerOptions' => options)
  # Note - Don't put more than one method per request even though you can.  It makes decoding errors much harder!

  @registrations[method] = [] if @registrations[method].nil?
  @registrations[method] << { registered: false, state: :pending, id: id }

  message_handler.protocol.send_client_request('client/registerCapability', params)
  true
end

#send_configuration_requestObject



43
44
45
46
47
48
49
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 43

def send_configuration_request
  params = LSP::ConfigurationParams.new.from_h!('items' => [])
  params.items << LSP::ConfigurationItem.new.from_h!('section' => 'puppet')

  message_handler.protocol.send_client_request('workspace/configuration', params)
  true
end

#unregister_capability(method) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/puppet-languageserver/session_state/language_client.rb', line 120

def unregister_capability(method)
  if @registrations[method].nil?
    PuppetLanguageServer.log_message(:debug, "No registrations to deregister for the #{method}")
    return true
  end

  params = LSP::UnregistrationParams.new.from_h!('unregisterations' => [])
  @registrations[method].each do |reg|
    next if reg[:id].nil?

    PuppetLanguageServer.log_message(:warn, "A dynamic registration/deregistration for the #{method} method, with id #{reg[:id]} is already in progress") if reg[:state] == :pending
    # Ignore registrations that don't need to be unregistered
    next if reg[:state] == :complete && !reg[:registered]

    params.unregisterations << LSP::Unregistration.new.from_h!('id' => reg[:id], 'method' => method)
    reg[:state] = :pending
  end

  if params.unregisterations.count.zero?
    PuppetLanguageServer.log_message(:debug, "Nothing to deregister for the #{method} method")
    return true
  end

  message_handler.protocol.send_client_request('client/unregisterCapability', params)
  true
end