Skip to content

Commit

Permalink
Turn off semantic highlighting on files with more than 100k chars
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Aug 23, 2024
1 parent 3547038 commit 8a9a1fd
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 2 deletions.
4 changes: 4 additions & 0 deletions lib/ruby_lsp/requests/semantic_highlighting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ module Requests
class SemanticHighlighting < Request
extend T::Sig

# This maximum number of characters for providing highlighting is the same limit imposed by the VS Code TypeScript
# extension. Even with delta requests, anything above this number lags the editor significantly
MAXIMUM_CHARACTERS_FOR_HIGHLIGHT = 100_000

class << self
extend T::Sig

Expand Down
29 changes: 28 additions & 1 deletion lib/ruby_lsp/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,25 @@ def text_document_did_open(message)
Document::LanguageId::Ruby
end

@store.set(
document = @store.set(
uri: text_document[:uri],
source: text_document[:text],
version: text_document[:version],
encoding: @global_state.encoding,
language_id: language_id,
)

if document.source.length > Requests::SemanticHighlighting::MAXIMUM_CHARACTERS_FOR_HIGHLIGHT
send_message(
Notification.new(
method: "window/showMessage",
params: Interface::ShowMessageParams.new(
type: Constant::MessageType::WARNING,
message: "This file is too long. For performance reasons, semantic highlighting will be disabled",
),
),
)
end
end
end

Expand Down Expand Up @@ -415,6 +427,11 @@ def run_combined_requests(message)
def text_document_semantic_tokens_full(message)
document = @store.get(message.dig(:params, :textDocument, :uri))

if document.source.length > Requests::SemanticHighlighting::MAXIMUM_CHARACTERS_FOR_HIGHLIGHT
send_empty_response(message[:id])
return
end

unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
send_empty_response(message[:id])
return
Expand All @@ -431,6 +448,11 @@ def text_document_semantic_tokens_full(message)
def text_document_semantic_tokens_delta(message)
document = @store.get(message.dig(:params, :textDocument, :uri))

if document.source.length > Requests::SemanticHighlighting::MAXIMUM_CHARACTERS_FOR_HIGHLIGHT
send_empty_response(message[:id])
return
end

unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
send_empty_response(message[:id])
return
Expand All @@ -454,6 +476,11 @@ def text_document_semantic_tokens_range(message)
uri = params.dig(:textDocument, :uri)
document = @store.get(uri)

if document.source.length > Requests::SemanticHighlighting::MAXIMUM_CHARACTERS_FOR_HIGHLIGHT
send_empty_response(message[:id])
return
end

unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
send_empty_response(message[:id])
return
Expand Down
2 changes: 1 addition & 1 deletion lib/ruby_lsp/store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get(uri)
version: Integer,
language_id: Document::LanguageId,
encoding: Encoding,
).void
).returns(Document[T.untyped])
end
def set(uri:, source:, version:, language_id:, encoding: Encoding::UTF_8)
@state[uri.to_s] = case language_id
Expand Down
49 changes: 49 additions & 0 deletions test/server_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,55 @@ def test_closing_document_before_computing_features_does_not_error
end
end

def test_semantic_highlighting_support_is_disabled_at_100k_characters
path_to_large_file = Gem.find_files("prism/**/node.rb").first
uri = URI::Generic.from_path(path: path_to_large_file)

capture_io do
@server.process_message({
method: "textDocument/didOpen",
params: {
textDocument: {
uri: uri,
text: File.read(path_to_large_file),
version: 1,
languageId: "ruby",
},
},
})

@server.process_message({
id: 1,
method: "textDocument/semanticTokens/full",
params: { textDocument: { uri: uri } },
})

result = find_message(RubyLsp::Result, id: 1)
assert_nil(result.response)

@server.process_message({
id: 2,
method: "textDocument/semanticTokens/full/delta",
params: { textDocument: { uri: uri } },
})

result = find_message(RubyLsp::Result, id: 2)
assert_nil(result.response)

@server.process_message({
id: 3,
method: "textDocument/semanticTokens/range",
params: {
textDocument: { uri: uri },
range: { start: { line: 0, character: 0 }, end: { line: 15, character: 0 } },
},
})

result = find_message(RubyLsp::Result, id: 3)
assert_nil(result.response)
end
end

private

def with_uninstalled_rubocop(&block)
Expand Down

0 comments on commit 8a9a1fd

Please sign in to comment.