From 554d7b98893b47faccfe35908de02e1ab4270ab5 Mon Sep 17 00:00:00 2001 From: Lukasz Samson Date: Thu, 8 Feb 2024 00:21:10 +0100 Subject: [PATCH] fix an edge case when reduced range may no longer contain cursor --- .../providers/selection_ranges.ex | 25 ++++---- .../lib/language_server/range_utils.ex | 5 ++ .../test/providers/selection_ranges_test.exs | 64 +++++++++++++++++++ 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/apps/language_server/lib/language_server/providers/selection_ranges.ex b/apps/language_server/lib/language_server/providers/selection_ranges.ex index b4f3529b8..e2937ffe5 100644 --- a/apps/language_server/lib/language_server/providers/selection_ranges.ex +++ b/apps/language_server/lib/language_server/providers/selection_ranges.ex @@ -188,8 +188,9 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRanges do {_, {start_line, start_character, _}, _} = previous_token {_, {end_line, end_character, _}, _} = token - if (start_line < line or (start_line == line and start_character <= character)) and - (end_line > line or (end_line == line and end_character >= character)) do + range_between_stop_tokens = range(start_line, start_character, end_line, end_character) + + if in?(range_between_stop_tokens, {line, character}) do # dbg({previous_token, after_previous, before_stop, token}) {end_line, end_character} = case before_stop do @@ -225,15 +226,17 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRanges do {start_line, start_character} end - # TODO - {:halt, - {token_tuple, - [ - intersection( - range(start_line, start_character, end_line, end_character), - inner_range - ) - ]}} + trimmed_range = + intersection( + range(start_line, start_character, end_line, end_character), + inner_range + ) + + if in?(trimmed_range, {line, character}) do + {:halt, {token_tuple, [trimmed_range]}} + else + {:halt, {token_tuple, []}} + end else {:cont, {token_tuple, []}} end diff --git a/apps/language_server/lib/language_server/range_utils.ex b/apps/language_server/lib/language_server/range_utils.ex index b410b54a2..b99fec638 100644 --- a/apps/language_server/lib/language_server/range_utils.ex +++ b/apps/language_server/lib/language_server/range_utils.ex @@ -15,6 +15,11 @@ defmodule ElixirLS.LanguageServer.RangeUtils do range(0, 0, Enum.count(lines) - 1, utf8_size) end + def in?(range(start_line, start_character, end_line, end_character), {line, character}) do + (start_line < line or (start_line == line and start_character <= character)) and + (end_line > line or (end_line == line and end_character >= character)) + end + def valid?(range(start_line, start_character, end_line, end_character)) when is_integer(start_line) and is_integer(end_line) and is_integer(start_character) and is_integer(end_character) do diff --git a/apps/language_server/test/providers/selection_ranges_test.exs b/apps/language_server/test/providers/selection_ranges_test.exs index d2b7dd0bb..fd1514c7e 100644 --- a/apps/language_server/test/providers/selection_ranges_test.exs +++ b/apps/language_server/test/providers/selection_ranges_test.exs @@ -996,4 +996,68 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRangesTest do assert_range(ranges, range(0, 6, 2, 6)) end end + + describe "map update" do + test "left side of |" do + text = """ + %{asd | a: 1, b: x} + """ + + ranges = get_ranges(text, 0, 3) + + # full range + assert_range(ranges, range(0, 0, 1, 0)) + # full map + assert_range(ranges, range(0, 0, 0, 19)) + # asd + assert_range(ranges, range(0, 2, 0, 5)) + end + + test "right side of |" do + text = """ + %{asd | a: 1, b: x} + """ + + ranges = get_ranges(text, 0, 9) + + # full range + assert_range(ranges, range(0, 0, 1, 0)) + # full map + assert_range(ranges, range(0, 0, 0, 19)) + # full keyword + assert_range(ranges, range(0, 8, 0, 18)) + # a: 1 + assert_range(ranges, range(0, 8, 0, 12)) + end + + test "left side of | near" do + text = """ + %{state | 1 => 1, counter: counter + to_dispatch, demand: demand - to_dispatch} + """ + + ranges = get_ranges(text, 0, 8) + + # full range + assert_range(ranges, range(0, 0, 1, 0)) + # full map + assert_range(ranges, range(0, 0, 0, 79)) + # | + assert_range(ranges, range(0, 8, 0, 9)) + end + + test "right side of | near" do + text = """ + %{state | 1 => 1, counter: counter + to_dispatch, demand: demand - to_dispatch} + """ + + ranges = get_ranges(text, 0, 9) + + # full range + assert_range(ranges, range(0, 0, 1, 0)) + # full map + assert_range(ranges, range(0, 0, 0, 79)) + # | + assert_range(ranges, range(0, 8, 0, 9)) + end + end end