Class: TypeProf::LSP::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/typeprof/lsp/server.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(core, reader, writer, url_schema: nil, publish_all_diagnostics: false) ⇒ Server

Returns a new instance of Server.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/typeprof/lsp/server.rb', line 47

def initialize(core, reader, writer, url_schema: nil, publish_all_diagnostics: false)
  @core = core
  @workspaces = {}
  @reader = reader
  @writer = writer
  @request_id = 0
  @running_requests_from_client = {}
  @running_requests_from_server = {}
  @open_texts = {}
  @exit = false
  @signature_enabled = true
  @url_schema = url_schema || (File::ALT_SEPARATOR != "\\" ? "file://" : "file:///")
  @publish_all_diagnostics = publish_all_diagnostics # TODO: implement more dedicated publish feature
end

Instance Attribute Details

#coreObject (readonly)

Returns the value of attribute core.



62
63
64
# File 'lib/typeprof/lsp/server.rb', line 62

def core
  @core
end

#open_textsObject (readonly)

Returns the value of attribute open_texts.



62
63
64
# File 'lib/typeprof/lsp/server.rb', line 62

def open_texts
  @open_texts
end

#signature_enabledObject

Returns the value of attribute signature_enabled.



63
64
65
# File 'lib/typeprof/lsp/server.rb', line 63

def signature_enabled
  @signature_enabled
end

Class Method Details

.start_socket(core) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/typeprof/lsp/server.rb', line 21

def self.start_socket(core)
  Socket.tcp_server_sockets("localhost", nil) do |servs|
    serv = servs[0].local_address
    $stdout << JSON.generate({
      host: serv.ip_address,
      port: serv.ip_port,
      pid: $$,
    })
    $stdout.flush

    $stdout = $stderr

    Socket.accept_loop(servs) do |sock|
      sock.set_encoding("UTF-8")
      begin
        reader = Reader.new(sock)
        writer = Writer.new(sock)
        new(core, reader, writer).run
      ensure
        sock.close
      end
      exit
    end
  end
end

.start_stdio(core) ⇒ Object



11
12
13
14
15
16
17
18
19
# File 'lib/typeprof/lsp/server.rb', line 11

def self.start_stdio(core)
  $stdin.binmode
  $stdout.binmode
  reader = Reader.new($stdin)
  writer = Writer.new($stdout)
  # pipe all builtin print output to stderr to avoid conflicting with lsp
  $stdout = $stderr
  new(core, reader, writer).run
end

Instance Method Details

#add_workspaces(folders) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/typeprof/lsp/server.rb', line 73

def add_workspaces(folders)
  folders.each do |path|
    conf_path = File.join(path, "typeprof.conf.json")
    if File.readable?(conf_path)
      conf = TypeProf::LSP.load_json_with_comments(conf_path, symbolize_names: true)
      if conf
        if conf[:typeprof_version] == "experimental"
          if conf[:analysis_unit_dirs].size >= 2
             puts "currently analysis_unit_dirs can have only one directory"
          end
          conf[:analysis_unit_dirs].each do |dir|
            dir = File.expand_path(dir, path)
            @workspaces[dir] = true
            @core.add_workspace(dir, conf[:rbs_dir])
          end
        else
          puts "Unknown typeprof_version: #{ conf[:typeprof_version] }"
        end
      end
    else
      puts "typeprof.conf.json is not found"
    end
  end
end

#cancel_request(id) ⇒ Object



141
142
143
144
# File 'lib/typeprof/lsp/server.rb', line 141

def cancel_request(id)
  req = @running_requests_from_client[id]
  req.cancel if req.respond_to?(:cancel)
end

#exitObject



146
147
148
# File 'lib/typeprof/lsp/server.rb', line 146

def exit
  @exit = true
end

#path_to_uri(path) ⇒ Object



65
66
67
# File 'lib/typeprof/lsp/server.rb', line 65

def path_to_uri(path)
  @url_schema + File.expand_path(path)
end

#publish_diagnostics(uri) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/typeprof/lsp/server.rb', line 150

def publish_diagnostics(uri)
  (@publish_all_diagnostics ? @open_texts : [[uri, @open_texts[uri]]]).each do |uri, text|
    diags = []
    if text
      @core.diagnostics(text.path) do |diag|
        diags << diag.to_lsp
      end
    end
    send_notification(
      "textDocument/publishDiagnostics",
      uri: uri,
      diagnostics: diags
    )
  end
end

#runObject



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/typeprof/lsp/server.rb', line 105

def run
  @reader.read do |json|
    if json[:method]
      # request or notification
      msg_class = Message.find(json[:method])
      if msg_class
        msg = msg_class.new(self, json)
        @running_requests_from_client[json[:id]] = msg if json[:id]
        msg.run
      else

      end
    else
      # response
      callback = @running_requests_from_server.delete(json[:id])
      callback&.call(json[:params], json[:error])
    end
    break if @exit
  end
end

#send_notification(method, **params) ⇒ Object



131
132
133
# File 'lib/typeprof/lsp/server.rb', line 131

def send_notification(method, **params)
  @writer.write(method: method, params: params)
end

#send_request(method, **params, &blk) ⇒ Object



135
136
137
138
139
# File 'lib/typeprof/lsp/server.rb', line 135

def send_request(method, **params, &blk)
  id = @request_id += 1
  @running_requests_from_server[id] = blk
  @writer.write(id: id, method: method, params: params)
end

#send_response(**msg) ⇒ Object



126
127
128
129
# File 'lib/typeprof/lsp/server.rb', line 126

def send_response(**msg)
  @running_requests_from_client.delete(msg[:id])
  @writer.write(**msg)
end

#target_path?(path) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
103
# File 'lib/typeprof/lsp/server.rb', line 98

def target_path?(path)
  @workspaces.each do |folder, _|
    return true if path.start_with?(folder)
  end
  return false
end

#uri_to_path(url) ⇒ Object



69
70
71
# File 'lib/typeprof/lsp/server.rb', line 69

def uri_to_path(url)
  url.delete_prefix(@url_schema)
end