diff --git a/server/buildoutls/md5sum.py b/server/buildoutls/md5sum.py index 410e332..95b1519 100644 --- a/server/buildoutls/md5sum.py +++ b/server/buildoutls/md5sum.py @@ -33,7 +33,7 @@ async def update_md5sum( ls.progress.begin( token, WorkDoneProgressBegin( - cancellable=True, # TODO actually support cancellation + cancellable=True, title=f"Updating md5sum for {url}", )) @@ -64,6 +64,8 @@ async def update_md5sum( message=f"{percentage:0.2f}% in {elapsed_time:0.2f}s", percentage=max(0, int(percentage)), )) + if ls.progress.tokens[token].cancelled(): + break hexdigest = m.hexdigest() @@ -88,13 +90,14 @@ async def update_md5sum( ) new_text = f"md5sum = {hexdigest}\n" - ls.progress.end(token, WorkDoneProgressEnd()) - ls.apply_edit( - WorkspaceEdit( - changes={ - md5sum_location.uri: - [TextEdit( - range=md5sum_location.range, - new_text=new_text, - )] - })) + if not ls.progress.tokens[token].cancelled(): + ls.progress.end(token, WorkDoneProgressEnd()) + ls.apply_edit( + WorkspaceEdit( + changes={ + md5sum_location.uri: + [TextEdit( + range=md5sum_location.range, + new_text=new_text, + )] + })) diff --git a/server/buildoutls/tests/conftest.py b/server/buildoutls/tests/conftest.py index 0490ef5..4ad54f3 100644 --- a/server/buildoutls/tests/conftest.py +++ b/server/buildoutls/tests/conftest.py @@ -1,3 +1,5 @@ +import collections +import concurrent.futures import os import urllib.parse from typing import Any @@ -55,6 +57,7 @@ def __init__(self): show_message_log = mock.Mock() apply_edit = mock.Mock() progress = mock.create_autospec(pygls.progress.Progress) + progress.tokens = collections.defaultdict(concurrent.futures.Future) server = FakeServer() diff --git a/server/buildoutls/tests/test_code_actions.py b/server/buildoutls/tests/test_code_actions.py index ac44ada..d905395 100644 --- a/server/buildoutls/tests/test_code_actions.py +++ b/server/buildoutls/tests/test_code_actions.py @@ -1,3 +1,5 @@ +import collections +import concurrent.futures import json import pathlib import textwrap @@ -550,6 +552,55 @@ async def test_update_md5sum_code_action_without_md5sum_option( }, ), ) +async def test_update_md5sum_code_action_cancelled( + server, + example_com_response, +) -> None: + + code_action_params = CodeActionParams( + text_document=TextDocumentIdentifier( + uri='file:///code_actions/update_md5sum.cfg'), + range=Range(start=Position(line=1, character=11), + end=Position(line=1, character=12)), + context=CodeActionContext(diagnostics=[])) + + code_actions = await lsp_code_action( + server, + _dump_and_load(code_action_params), + ) + assert isinstance(code_actions, list) + assert code_actions == [ + CodeAction( + title='Update md5sum', + kind=CodeActionKind.QuickFix, + command=Command( + title='Update md5sum', + command=COMMAND_UPDATE_MD5SUM, + arguments=[ + UpdateMD5SumCommandParams( + document_uri='file:///code_actions/update_md5sum.cfg', + section_name='section', + ), + ], + ), + ) + ] + assert isinstance(code_actions[0].command, Command) + assert code_actions[0].command.arguments + + def cancelled_future() -> concurrent.futures.Future[None]: + f: concurrent.futures.Future[None] = concurrent.futures.Future() + f.cancel() + return f + + server.progress.tokens = collections.defaultdict(cancelled_future) + + await command_update_md5sum( + server, + cast(List[UpdateMD5SumCommandParams], code_actions[0].command.arguments)) + server.apply_edit.assert_not_called() + + @pytest.mark.parametrize( 'range_', [