lib/solargraph/language_server/progress.rb
# frozen_string_literal: true require 'securerandom' module Solargraph module LanguageServer # Progress notification handling for language server hosts. # class Progress WAITING = :waiting CREATED = :created FINISHED = :finished # @return [String] attr_reader :uuid # @return [String] attr_reader :title # @return [String, nil] attr_reader :kind # @return [String, nil] attr_reader :message # @return [Integer] attr_reader :percentage # @return [Symbol] attr_reader :status # @param title [String] def initialize title @title = title @uuid = SecureRandom.uuid @percentage = 0 @status = WAITING end # @param message [String] # @param percentage [Integer] def begin message, percentage @kind = 'begin' @message = message @percentage = percentage end # @param message [String] # @param percentage [Integer] def report message, percentage @kind = 'report' @message = message @percentage = percentage end # @param message [String] def finish message @kind = 'end' @message = message @percentage = 100 true end # @param host [Solargraph::LanguageServer::Host] def send host return unless host.client_supports_progress? && !finished? message = build create(host) host.send_notification '$/progress', message @status = FINISHED if kind == 'end' keep_alive host end def created? [CREATED, FINISHED].include?(status) end def finished? status == FINISHED end private # @param host [Solargraph::LanguageServer::Host] # @return [void] def create host return if created? host.send_request 'window/workDoneProgress/create', { token: uuid } @status = CREATED end def build { token: uuid, value: { kind: kind, cancellable: false }.merge(build_value) } end def build_value case kind when 'begin' { title: title, message: message, percentage: percentage } when 'report' { message: message, percentage: percentage } when 'end' { message: message } else raise "Invalid progress kind #{kind}" end end # @param host [Host] def keep_alive host mutex.synchronize { @last = Time.now } @keep_alive ||= Thread.new do until finished? sleep 10 break if finished? next if mutex.synchronize { Time.now - @last < 10 } send host end end end def mutex @mutex ||= Mutex.new end end end end