Skip to content

Commit

Permalink
Adds Progress/WorkDone types
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAngryByrd authored and baronfel committed Nov 30, 2022
1 parent a201c71 commit 0fc8dbc
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 40 deletions.
21 changes: 20 additions & 1 deletion src/Client.fs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ type ILspClient =
/// on the client side.
abstract member TextDocumentPublishDiagnostics: PublishDiagnosticsParams -> Async<unit>

/// The window/workDoneProgress/create request is sent from the server to the client to ask the client to create a work done progress.
abstract member WorkDoneProgressCreate: ProgressToken -> AsyncLspResult<unit>

/// The base protocol offers also support to report progress in a generic fashion.
/// This mechanism can be used to report any kind of progress including work done progress
/// (usually used to report progress in the user interface using a progress bar) and
/// partial result progress to support streaming of results.
abstract member Progress: ProgressToken * 'Progress -> Async<unit>

[<AbstractClass>]
type LspClient() =

Expand Down Expand Up @@ -208,6 +217,14 @@ type LspClient() =

default __.TextDocumentPublishDiagnostics(_) = ignoreNotification

abstract member Progress: ProgressToken * 'Progress -> Async<unit>

default __.Progress(_, _) = ignoreNotification

/// The window/workDoneProgress/create request is sent from the server to the client to ask the client to create a work done progress.
abstract member WorkDoneProgressCreate: ProgressToken -> AsyncLspResult<unit>
default __.WorkDoneProgressCreate(_) = notImplemented

interface ILspClient with
member this.WindowShowMessage(p: ShowMessageParams) = this.WindowShowMessage(p)
member this.WindowShowMessageRequest(p: ShowMessageRequestParams) = this.WindowShowMessageRequest(p)
Expand All @@ -220,4 +237,6 @@ type LspClient() =
member this.WorkspaceApplyEdit(p: ApplyWorkspaceEditParams) = this.WorkspaceApplyEdit(p)
member this.WorkspaceSemanticTokensRefresh() = this.WorkspaceSemanticTokensRefresh()
member this.WorkspaceInlayHintRefresh() = this.WorkspaceInlayHintRefresh()
member this.TextDocumentPublishDiagnostics(p: PublishDiagnosticsParams) = this.TextDocumentPublishDiagnostics(p)
member this.TextDocumentPublishDiagnostics(p: PublishDiagnosticsParams) = this.TextDocumentPublishDiagnostics(p)
member this.WorkDoneProgressCreate(token: ProgressToken) = this.WorkDoneProgressCreate(token)
member this.Progress(token, data) = this.Progress(token, data)
1 change: 1 addition & 0 deletions src/LanguageServerProtocol.fs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ module Server =
"workspace/didDeleteFiles", requestHandling (fun s p -> s.WorkspaceDidDeleteFiles(p) |> notificationSuccess)
"workspace/symbol", requestHandling (fun s p -> s.WorkspaceSymbol(p))
"workspace/executeCommand", requestHandling (fun s p -> s.WorkspaceExecuteCommand(p))
"window/workDoneProgress/cancel", requestHandling (fun s p -> s.WorkDoneProgessCancel(p) |> notificationSuccess)
"shutdown", requestHandling (fun s () -> s.Shutdown() |> notificationSuccess)
"exit", requestHandling (fun s () -> s.Exit() |> notificationSuccess) ]
|> Map.ofList
Expand Down
17 changes: 16 additions & 1 deletion src/Server.fs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ type ILspServer =
/// then an inlay hint with a label part without a location needs to be resolved using the `inlayHint/resolve` request before it can be used.
abstract member InlayHintResolve: InlayHint -> AsyncLspResult<InlayHint>

/// The `window/workDoneProgress/cancel` notification is sent from the client to the server to cancel a
/// progress initiated on the server side using the `window/workDoneProgress/create`. The progress need
/// not be marked as cancellable to be cancelled and a client may cancel a progress for any number of
/// reasons: in case of error, reloading a workspace etc.
abstract member WorkDoneProgessCancel: ProgressToken -> Async<unit>

[<AbstractClass>]
type LspServer() =
abstract member Dispose: unit -> unit
Expand Down Expand Up @@ -646,6 +652,14 @@ type LspServer() =

default __.InlayHintResolve(_) = notImplemented

/// The `window/workDoneProgress/cancel` notification is sent from the client to the server to cancel a
/// progress initiated on the server side using the `window/workDoneProgress/create`. The progress need
/// not be marked as cancellable to be cancelled and a client may cancel a progress for any number of
/// reasons: in case of error, reloading a workspace etc.
abstract member WorkDoneProgessCancel: ProgressToken -> Async<unit>

default __.WorkDoneProgessCancel(_) = ignoreNotification

interface ILspServer with
member this.Dispose() = this.Dispose()
member this.Initialize(p: InitializeParams) = this.Initialize(p)
Expand Down Expand Up @@ -706,4 +720,5 @@ type LspServer() =

member this.TextDocumentSemanticTokensRange(p: SemanticTokensRangeParams) = this.TextDocumentSemanticTokensRange(p)
member this.TextDocumentInlayHint(p: InlayHintParams) = this.TextDocumentInlayHint(p)
member this.InlayHintResolve(p: InlayHint) = this.InlayHintResolve(p)
member this.InlayHintResolve(p: InlayHint) = this.InlayHintResolve(p)
member this.WorkDoneProgessCancel(token) = this.WorkDoneProgessCancel(token)
176 changes: 159 additions & 17 deletions src/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,15 @@ type InlayHintWorkspaceClientCapabilities =
/// change that requires such a calculation.
RefreshSupport: bool option }

type CodeLensWorkspaceClientCapabilities = {
/// Whether the client implementation supports a refresh request sent from the
/// server to the client.
///
/// Note that this event is global and will force the client to refresh all
/// code lenses currently shown. It should be used with absolute care and is
/// useful for situation where a server for example detect a project wide
/// change that requires such a calculation.
RefreshSupport: bool option
}
type CodeLensWorkspaceClientCapabilities =
{ /// Whether the client implementation supports a refresh request sent from the
/// server to the client.
///
/// Note that this event is global and will force the client to refresh all
/// code lenses currently shown. It should be used with absolute care and is
/// useful for situation where a server for example detect a project wide
/// change that requires such a calculation.
RefreshSupport: bool option }

/// Workspace specific client capabilities.
type WorkspaceClientCapabilities =
Expand Down Expand Up @@ -804,6 +803,48 @@ type TextDocumentClientCapabilities =
/// @since 3.17.0
InlayHint: InlayHintClientCapabilities option }

/// Client capabilities for the showDocument request.
///
/// @since 3.16.0
type ShowDocumentClientCapabilities =
{ /// The client has support for the showDocument request
support: bool }

/// Capabilities specific to the `MessageActionItem` type
type MessageActionItemCapabilties =
{ /// Whether the client supports additional attributes which
/// are preserved and send back to the server in the
/// request's response.
additionalPropertiesSupport: bool option }

/// Show message request client capabilities
type ShowMessageRequestClientCapabilities =
{ /// Capabilities specific to the `MessageActionItem` type
messageActionItem: MessageActionItemCapabilties option }

type WindowClientCapabilities =
{ ///
/// It indicates whether the client supports server initiated
/// progress using the `window/workDoneProgress/create` request.
///
/// The capability also controls Whether client supports handling
/// of progress notifications. If set servers are allowed to report a
/// `workDoneProgress` property in the request specific server
/// capabilities.
///
/// @since 3.15.0
workDoneProgress: bool option

/// Capabilities specific to the showMessage request.
///
/// @since 3.16.0
showMessage: ShowMessageRequestClientCapabilities option

/// Capabilities specific to the showDocument request.
///
/// @since 3.16.0
showDocument: ShowDocumentClientCapabilities option }

type ClientCapabilities =
{ /// Workspace specific client capabilities.
Workspace: WorkspaceClientCapabilities option
Expand All @@ -812,7 +853,10 @@ type ClientCapabilities =
TextDocument: TextDocumentClientCapabilities option

/// Experimental client capabilities.
Experimental: JToken option }
Experimental: JToken option

/// Window specific client capabilities.
Window: WindowClientCapabilities option }

type WorkspaceFolder =
{ /// The associated URI for this workspace folder.
Expand Down Expand Up @@ -1942,11 +1986,11 @@ type ColorPresentation =
type CodeActionKind = string

type CodeActionTriggerKind =
/// Code actions were explicitly requested by the user or by an extension.
| Invoked = 1
/// Code actions were requested automatically.
/// This typically happens when current selection in a file changes, but can also be triggered when file content changes.
| Automatic = 2
/// Code actions were explicitly requested by the user or by an extension.
| Invoked = 1
/// Code actions were requested automatically.
/// This typically happens when current selection in a file changes, but can also be triggered when file content changes.
| Automatic = 2

/// Contains additional diagnostic information about the context in which
/// a code action is run.
Expand Down Expand Up @@ -2284,4 +2328,102 @@ type InlayHint =

/// A data entry field that is preserved on a inlay hint between
/// a `textDocument/inlayHint` and a `inlayHint/resolve` request.
Data: LSPAny option }
Data: LSPAny option }

type ProgressToken = U2<int, string>

type WorkDoneProgressCreateParams =
{ ///The token to be used to report progress.
token: ProgressToken }

/// The base protocol offers also support to report progress in a generic fashion.
/// This mechanism can be used to report any kind of progress including work done progress
/// (usually used to report progress in the user interface using a progress bar) and partial
/// result progress to support streaming of results.
type ProgressParams<'T> =
{ /// The progress token provided by the client or server.
token: ProgressToken
/// The progress data.
value: 'T }

type WorkDoneProgressKind =
| Begin
| Report
| End
override x.ToString() =
match x with
| Begin -> "begin"
| Report -> "report"
| End -> "end"

type WorkDoneProgressEnd =
{ /// WorkDoneProgressKind.End
kind: string
/// Optional, a final message indicating to for example indicate the outcome of the operation.
message: string option }
static member Create(?message) = { kind = WorkDoneProgressKind.End.ToString(); message = message }

type WorkDoneProgressBegin =
{ /// WorkDoneProgressKind.Begin
kind: string

/// Mandatory title of the progress operation. Used to briefly inform about
/// the kind of operation being performed.
///
/// Examples: "Indexing" or "Linking dependencies".
title: string option
/// Controls if a cancel button should show to allow the user to cancel the
/// long running operation. Clients that don't support cancellation are allowed
/// to ignore the setting.
cancellable: bool option
/// Optional, more detailed associated progress message. Contains
/// complementary information to the `title`.
///
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
/// If unset, the previous progress message (if any) is still valid.
message: string option
/// Optional progress percentage to display (value 100 is considered 100%).
/// If not provided infinite progress is assumed and clients are allowed
/// to ignore the `percentage` value in subsequent in report notifications.
///
/// The value should be steadily rising. Clients are free to ignore values
/// that are not following this rule. The value range is [0, 100].
percentage: uint option }

static member Create(title, ?cancellable, ?message, ?percentage) =
{ kind = WorkDoneProgressKind.Begin.ToString()
title = Some title
cancellable = cancellable
message = message
percentage = percentage }

type WorkDoneProgressReport =
{ /// WorkDoneProgressKind.Report
kind: string
/// Controls enablement state of a cancel button.
///
/// Clients that don't support cancellation or don't support controlling the button's
/// enablement state are allowed to ignore the property.
cancellable: bool option
/// Optional, more detailed associated progress message. Contains
/// complementary information to the `title`.
///
/// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
/// If unset, the previous progress message (if any) is still valid.
message: string option
/// Optional progress percentage to display (value 100 is considered 100%).
/// If not provided infinite progress is assumed and clients are allowed
/// to ignore the `percentage` value in subsequent in report notifications.
///
/// The value should be steadily rising. Clients are free to ignore values
/// that are not following this rule. The value range is [0, 100].
percentage: uint option }

static member Create(?cancellable, ?message, ?percentage) =
{ kind = WorkDoneProgressKind.Report.ToString()
cancellable = cancellable
message = message
percentage = percentage }

/// The token to be used to report progress.
type WorkDoneProgressCancelParams = { token: ProgressToken }
3 changes: 2 additions & 1 deletion tests/Benchmarks.fs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,8 @@ type MultipleTypesBenchmarks() =
Some
{ DynamicRegistration = Some true
ResolveSupport = Some { Properties = [| "Tooltip"; "Position"; "TextEdits" |] } } }
Experimental = None }
Experimental = None
Window = None }
trace = None
WorkspaceFolders =
Some [| { Uri = "..."; Name = "foo" }
Expand Down
40 changes: 20 additions & 20 deletions tests/Program.fs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
module Ionide.LanguageServerProtocol.Tests.Root

open Expecto.Tests

[<EntryPoint>]
let main args =
let (|ShouldRunBenchmarks|_|) (args: string []) =
let nArgs = args.Length
let markers = [| "--benchmark"; "--benchmarks"; "-b" |]

let args =
args
|> Array.filter (fun arg -> markers |> Array.contains arg |> not)

if args.Length = nArgs then None else Some args

match args with
| ShouldRunBenchmarks args ->
// `--filter *` to run all
Benchmarks.run args
module Ionide.LanguageServerProtocol.Tests.Root

open Expecto.Tests

[<EntryPoint>]
let main args =
let (|ShouldRunBenchmarks|_|) (args: string []) =
let nArgs = args.Length
let markers = [| "--benchmark"; "--benchmarks"; "-b" |]

let args =
args
|> Array.filter (fun arg -> markers |> Array.contains arg |> not)

if args.Length = nArgs then None else Some args

match args with
| ShouldRunBenchmarks args ->
// `--filter *` to run all
Benchmarks.run args
| _ -> Expecto.Tests.runTestsWithCLIArgs [ Sequenced ] args Tests.tests

0 comments on commit 0fc8dbc

Please sign in to comment.