Class: Mui::Lsp::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/mui/lsp/client.rb

Overview

LSP Client - manages connection to a language server

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command:, root_path:, on_notification: nil) ⇒ Client



11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/mui/lsp/client.rb', line 11

def initialize(command:, root_path:, on_notification: nil)
  @command = command
  @root_path = root_path
  @root_uri = "file://#{root_path}"
  @on_notification = on_notification
  @initialized = false
  @server_capabilities = {}
  @process = nil
  @io = nil
  @request_manager = RequestManager.new
  @reader_thread = nil
  @running = false
end

Instance Attribute Details

#initializedObject (readonly)

Returns the value of attribute initialized.



9
10
11
# File 'lib/mui/lsp/client.rb', line 9

def initialized
  @initialized
end

#last_stderrObject (readonly)

Returns the value of attribute last_stderr.



9
10
11
# File 'lib/mui/lsp/client.rb', line 9

def last_stderr
  @last_stderr
end

#root_uriObject (readonly)

Returns the value of attribute root_uri.



9
10
11
# File 'lib/mui/lsp/client.rb', line 9

def root_uri
  @root_uri
end

#server_capabilitiesObject (readonly)

Returns the value of attribute server_capabilities.



9
10
11
# File 'lib/mui/lsp/client.rb', line 9

def server_capabilities
  @server_capabilities
end

Instance Method Details

#completion(uri:, line:, character:, &callback) ⇒ Object



115
116
117
118
119
120
# File 'lib/mui/lsp/client.rb', line 115

def completion(uri:, line:, character:, &callback)
  request("textDocument/completion", {
            textDocument: { uri: uri },
            position: { line: line, character: character }
          }, &callback)
end

#definition(uri:, line:, character:, &callback) ⇒ Object



100
101
102
103
104
105
# File 'lib/mui/lsp/client.rb', line 100

def definition(uri:, line:, character:, &callback)
  request("textDocument/definition", {
            textDocument: { uri: uri },
            position: { line: line, character: character }
          }, &callback)
end

#did_change(uri:, version:, changes:) ⇒ Object



133
134
135
136
137
138
# File 'lib/mui/lsp/client.rb', line 133

def did_change(uri:, version:, changes:)
  notify("textDocument/didChange", {
           textDocument: { uri: uri, version: version },
           contentChanges: changes
         })
end

#did_close(uri:) ⇒ Object



146
147
148
149
150
# File 'lib/mui/lsp/client.rb', line 146

def did_close(uri:)
  notify("textDocument/didClose", {
           textDocument: { uri: uri }
         })
end

#did_open(uri:, language_id:, version:, text:) ⇒ Object



122
123
124
125
126
127
128
129
130
131
# File 'lib/mui/lsp/client.rb', line 122

def did_open(uri:, language_id:, version:, text:)
  notify("textDocument/didOpen", {
           textDocument: {
             uri: uri,
             languageId: language_id,
             version: version,
             text: text
           }
         })
end

#did_save(uri:, text: nil) ⇒ Object



140
141
142
143
144
# File 'lib/mui/lsp/client.rb', line 140

def did_save(uri:, text: nil)
  params = { textDocument: { uri: uri } }
  params[:text] = text if text
  notify("textDocument/didSave", params)
end

#hover(uri:, line:, character:, &callback) ⇒ Object



93
94
95
96
97
98
# File 'lib/mui/lsp/client.rb', line 93

def hover(uri:, line:, character:, &callback)
  request("textDocument/hover", {
            textDocument: { uri: uri },
            position: { line: line, character: character }
          }, &callback)
end

#notify(method, params = nil) ⇒ Object



84
85
86
87
88
89
90
91
# File 'lib/mui/lsp/client.rb', line 84

def notify(method, params = nil)
  return unless @running

  message = JsonRpcIO.build_notification(method: method, params: params)
  return if @io.write_message(message)

  @running = false
end

#references(uri:, line:, character:, include_declaration: true, &callback) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/mui/lsp/client.rb', line 107

def references(uri:, line:, character:, include_declaration: true, &callback)
  request("textDocument/references", {
            textDocument: { uri: uri },
            position: { line: line, character: character },
            context: { includeDeclaration: include_declaration }
          }, &callback)
end

#request(method, params = nil, &callback) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/mui/lsp/client.rb', line 71

def request(method, params = nil, &callback)
  return nil unless @running

  id = @request_manager.register(callback)
  message = JsonRpcIO.build_request(id: id, method: method, params: params)
  unless @io.write_message(message)
    @running = false
    @request_manager.cancel(id)
    return nil
  end
  id
end

#running?Boolean



63
64
65
# File 'lib/mui/lsp/client.rb', line 63

def running?
  @running && @initialized
end

#startObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/mui/lsp/client.rb', line 25

def start
  return if @running

  # Split command into array for proper shell handling
  cmd_parts = @command.is_a?(Array) ? @command : @command.split(/\s+/)
  stdin, stdout, stderr, @process = Open3.popen3(*cmd_parts)
  @io = JsonRpcIO.new(input: stdout, output: stdin)
  @stderr = stderr
  @running = true
  @init_mutex = Mutex.new
  @init_cv = ConditionVariable.new

  start_reader_thread
  start_stderr_thread
  initialize_server

  # Wait for initialization to complete (with timeout)
  @init_mutex.synchronize do
    unless @initialized
      @init_cv.wait(@init_mutex, 10) # 10 second timeout
    end
  end
end

#started?Boolean



67
68
69
# File 'lib/mui/lsp/client.rb', line 67

def started?
  @running
end

#stopObject



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/mui/lsp/client.rb', line 49

def stop
  return unless @running

  @running = false
  shutdown
  @reader_thread&.join(2)
  begin
    @process&.kill
  rescue StandardError
    nil
  end
  @request_manager.cancel_all
end