Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a strategy pattern and inject encoder to process semantic tokens #94

Merged
merged 10 commits into from
May 13, 2022
61 changes: 61 additions & 0 deletions lib/ruby_lsp/encoder/relative.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

module RubyLsp
module Encoder
class Relative
TOKEN_TYPES = [
:variable,
:method,
].freeze
TOKEN_MODIFIERS = [].freeze
wildmaples marked this conversation as resolved.
Show resolved Hide resolved

def initialize(request)
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
@tokens = request.run
@delta = []
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
@current_row = 0
@current_column = 0
end

def run
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
@tokens.each do |token|
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
compute_delta(token) do |delta_line, delta_column|
@delta.push(delta_line, delta_column, token.length, TOKEN_TYPES.index(token.classification), 0)
end
end
wildmaples marked this conversation as resolved.
Show resolved Hide resolved

LanguageServer::Protocol::Interface::SemanticTokens.new(data: @delta)
end

# The delta array is computed according to the LSP specification:
# > The protocol for the token format relative uses relative
# > positions, because most tokens remain stable relative to
# > each other when edits are made in a file. This simplifies
# > the computation of a delta if a server supports it. So each
# > token is represented using 5 integers.

# For more information on how each number is calculated, read:
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens
def compute_delta(token)
row = token.location.start_line - 1
column = token.location.start_column

if row < @current_row
raise InvalidTokenRowError, "Invalid token row detected: " \
"Ensure tokens are added in the expected order."
end

delta_line = row - @current_row

delta_column = column
delta_column -= @current_column if delta_line == 0

yield delta_line, delta_column

@current_row = row
@current_column = column
end
wildmaples marked this conversation as resolved.
Show resolved Hide resolved

class InvalidTokenRowError < StandardError; end
end
end
end
7 changes: 4 additions & 3 deletions lib/ruby_lsp/handler.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require "ruby_lsp/encoder/relative"
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
require "ruby_lsp/requests"
require "ruby_lsp/store"
require "benchmark"
Expand Down Expand Up @@ -69,8 +70,8 @@ def respond_with_capabilities(enabled_features)
Interface::SemanticTokensRegistrationOptions.new(
document_selector: { scheme: "file", language: "ruby" },
legend: Interface::SemanticTokensLegend.new(
token_types: Requests::SemanticHighlighting::TOKEN_TYPES,
token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS
token_types: Encoder::Relative::TOKEN_TYPES,
token_modifiers: Encoder::Relative::TOKEN_MODIFIERS
),
range: false,
full: {
Expand Down Expand Up @@ -125,7 +126,7 @@ def respond_with_selection_ranges(uri, positions)

def respond_with_semantic_highlighting(uri)
store.cache_fetch(uri, :semantic_highlighting) do |document|
Requests::SemanticHighlighting.run(document)
Encoder::Relative.new(Requests::SemanticHighlighting.new(document)).run
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
end
end

Expand Down
46 changes: 3 additions & 43 deletions lib/ruby_lsp/requests/semantic_highlighting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,18 @@ module Requests
# end
# ```
class SemanticHighlighting < BaseRequest
TOKEN_TYPES = [
:variable,
:method,
].freeze
TOKEN_MODIFIERS = [].freeze
SemanticToken = Struct.new(:location, :length, :classification)
wildmaples marked this conversation as resolved.
Show resolved Hide resolved

def initialize(document)
super

@tokens = []
@tree = document.tree
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
@current_row = 0
@current_column = 0
end

def run
visit(@tree)
LanguageServer::Protocol::Interface::SemanticTokens.new(data: @tokens)
@tokens
wildmaples marked this conversation as resolved.
Show resolved Hide resolved
end

def visit_m_assign(node)
Expand Down Expand Up @@ -88,42 +82,8 @@ def visit_vcall(node)

def add_token(location, classification)
length = location.end_char - location.start_char

compute_delta(location) do |delta_line, delta_column|
@tokens.push(delta_line, delta_column, length, TOKEN_TYPES.index(classification), 0)
end
end

# The delta array is computed according to the LSP specification:
# > The protocol for the token format relative uses relative
# > positions, because most tokens remain stable relative to
# > each other when edits are made in a file. This simplifies
# > the computation of a delta if a server supports it. So each
# > token is represented using 5 integers.

# For more information on how each number is calculated, read:
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens
def compute_delta(location)
row = location.start_line - 1
column = location.start_column

if row < @current_row
raise InvalidTokenRowError, "Invalid token row detected: " \
"Ensure tokens are added in the expected order."
end

delta_line = row - @current_row

delta_column = column
delta_column -= @current_column if delta_line == 0

yield delta_line, delta_column

@current_row = row
@current_column = column
@tokens.push(SemanticToken.new(location, length, classification))
end

class InvalidTokenRowError < StandardError; end
end
end
end
6 changes: 5 additions & 1 deletion test/requests/semantic_highlighting_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,13 @@ def some_method

def assert_tokens(expected, source_code)
document = RubyLsp::Document.new(source_code)
encoded_tokens = RubyLsp::Encoder::Relative.new(
RubyLsp::Requests::SemanticHighlighting.new(document)
).run

assert_equal(
inline_tokens(expected),
RubyLsp::Requests::SemanticHighlighting.run(document).data
encoded_tokens.data
)
end

Expand Down