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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get proof blocks api #960

Merged
merged 10 commits into from
Dec 11, 2024
1 change: 0 additions & 1 deletion client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
integer
} from 'vscode-languageclient/node';

import {decorationsManual, decorationsContinuous, decorationsErrorAnimation} from './Decorations';
Expand Down
18 changes: 17 additions & 1 deletion client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import SearchViewProvider from './panels/SearchViewProvider';
import {
CoqLogMessage,
DocumentProofsRequest,
DocumentProofsResponse,
ErrorAlertNotification,
MoveCursorNotification,
ProofViewNotification,
Expand All @@ -41,8 +43,8 @@
sendStepBackward
} from './manualChecking';
import {
makeVersionedDocumentId,

Check warning on line 46 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, fatalwarnings)

'makeVersionedDocumentId' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 46 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.19.0)

'makeVersionedDocumentId' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 46 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.18.0)

'makeVersionedDocumentId' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 46 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, dev)

'makeVersionedDocumentId' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 46 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.20.0)

'makeVersionedDocumentId' is defined but never used. Allowed unused vars must match /^_/u
isMouseOrKeyboardEvent

Check warning on line 47 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, fatalwarnings)

'isMouseOrKeyboardEvent' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 47 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.19.0)

'isMouseOrKeyboardEvent' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 47 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.18.0)

'isMouseOrKeyboardEvent' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 47 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, dev)

'isMouseOrKeyboardEvent' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 47 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.20.0)

'isMouseOrKeyboardEvent' is defined but never used. Allowed unused vars must match /^_/u
} from './utilities/utils';
import { DocumentStateViewProvider } from './panels/DocumentStateViewProvider';
import VsCoqToolchainManager, {ToolchainError, ToolChainErrorCode} from './utilities/toolchain';
Expand All @@ -59,6 +61,14 @@
});
}

const getDocumentProofs = (uri: Uri) => {
const textDocument = TextDocumentIdentifier.create(uri.toString());
const params: DocumentProofsRequest = {textDocument};
const req = new RequestType<DocumentProofsRequest, DocumentProofsResponse, void>("vscoq/documentProofs");
Client.writeToVscoq2Channel("Getting proofs for: " + uri.toString());
return client.sendRequest(req, params);
};

// Watch for files being added or removed
workspace.onDidCreateFiles(checkInCoqProject);
workspace.onDidDeleteFiles(checkInCoqProject);
Expand Down Expand Up @@ -193,7 +203,7 @@
const req = new RequestType<ResetCoqRequest, ResetCoqResponse, void>("vscoq/resetCoq");
Client.writeToVscoq2Channel(uri.toString());
client.sendRequest(req, params).then(
(res) => {

Check warning on line 206 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, fatalwarnings)

'res' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 206 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.19.0)

'res' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 206 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.18.0)

'res' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 206 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, dev)

'res' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 206 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.20.0)

'res' is defined but never used. Allowed unused args must match /^_/u
GoalPanel.resetGoalPanel();
},
(err) => {
Expand Down Expand Up @@ -351,7 +361,7 @@
}
}));

let goalsHook = window.onDidChangeTextEditorSelection(

Check warning on line 364 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, fatalwarnings)

'goalsHook' is assigned a value but never used. Allowed unused vars must match /^_/u

Check warning on line 364 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.19.0)

'goalsHook' is assigned a value but never used. Allowed unused vars must match /^_/u

Check warning on line 364 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.18.0)

'goalsHook' is assigned a value but never used. Allowed unused vars must match /^_/u

Check warning on line 364 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, dev)

'goalsHook' is assigned a value but never used. Allowed unused vars must match /^_/u

Check warning on line 364 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.20.0)

'goalsHook' is assigned a value but never used. Allowed unused vars must match /^_/u
(evt: TextEditorSelectionChangeEvent) => {
if (evt.textEditor.document.languageId === "coq"
&& workspace.getConfiguration('vscoq.proof').mode === 1)
Expand All @@ -361,14 +371,20 @@
}
);

window.onDidChangeActiveTextEditor(editor => {

Check warning on line 374 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, fatalwarnings)

'editor' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 374 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.19.0)

'editor' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 374 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.18.0)

'editor' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 374 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / dev-setup-opam (ubuntu-latest, 4.14.x, dev)

'editor' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 374 in client/src/extension.ts

View workflow job for this annotation

GitHub Actions / install-opam (ubuntu-latest, 4.14.x, 8.20.0)

'editor' is defined but never used. Allowed unused args must match /^_/u
client.updateHightlights();
});

});

context.subscriptions.push(client);
}
}

const externalApi = {
getDocumentProofs
};

return externalApi;

}

Expand Down
24 changes: 24 additions & 0 deletions client/src/protocol/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,27 @@ export interface ResetCoqRequest {
}

export interface ResetCoqResponse {};

export interface DocumentProofsRequest {
textDocument: TextDocumentIdentifier;
}

type ProofStatement = {
range: Range;
statement: string;
}

type ProofStep = {
range: Range;
tactic: string;
};

type ProofBlock = {
statement: ProofStatement;
range: Range;
steps: ProofStep[];
};

export interface DocumentProofsResponse {
proofs: ProofBlock[];
}
55 changes: 43 additions & 12 deletions language-server/dm/document.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@ type proof_block_type =
| DefinitionType of Decls.definition_object_kind
| Other

type proof_step = {
id: sentence_id;
tactic: string;
range: Range.t;
}

type outline_element = {
id: sentence_id;
name: string;
type_: proof_block_type;
statement: string;
proof: proof_step list;
range: Range.t
}

Expand Down Expand Up @@ -132,11 +139,20 @@ let range_of_sentence raw (sentence : sentence) =
let end_ = RawDocument.position_of_loc raw sentence.stop in
Range.{ start; end_ }

let string_of_sentence raw (sentence: sentence) =
let string = RawDocument.string_in_range raw sentence.start sentence.stop in
string

let range_of_sentence_with_blank_space raw (sentence : sentence) =
let start = RawDocument.position_of_loc raw sentence.parsing_start in
let end_ = RawDocument.position_of_loc raw sentence.stop in
Range.{ start; end_ }

let string_of_id document id =
match SM.find_opt id document.sentences_by_id with
| None -> CErrors.anomaly Pp.(str"Trying to get range of non-existing sentence " ++ Stateid.print id)
| Some sentence -> string_of_sentence document.raw_doc sentence

let range_of_id document id =
match SM.find_opt id document.sentences_by_id with
| None -> CErrors.anomaly Pp.(str"Trying to get range of non-existing sentence " ++ Stateid.print id)
Expand All @@ -147,19 +163,29 @@ let range_of_id_with_blank_space document id =
| None -> CErrors.anomaly Pp.(str"Trying to get range of non-existing sentence " ++ Stateid.print id)
| Some sentence -> range_of_sentence_with_blank_space document.raw_doc sentence

let push_proof_step_in_outline document id (outline : outline) =
let range = range_of_id document id in
let tactic = string_of_id document id in
let proof_step = {id; tactic; range} in
match outline with
| [] -> outline
| e :: l ->
let proof = proof_step :: e.proof in
{e with proof} :: l

let record_outline document id (ast : Synterp.vernac_control_entry) classif (outline : outline) =
let open Vernacextend in
match classif with
| VtProofStep _ | VtQed _ -> push_proof_step_in_outline document id outline
| VtStartProof (_, names) ->
let vernac_gen_expr = ast.v.expr in
let type_, statement = match vernac_gen_expr with
| VernacSynterp _ -> None, ""
let type_ = match vernac_gen_expr with
| VernacSynterp _ -> None
| VernacSynPure pure ->
match pure with
| Vernacexpr.VernacStartTheoremProof (kind, _) -> Some (TheoremKind kind), "theorem"
| Vernacexpr.VernacDefinition ((_, def), _, _) -> Some (DefinitionType def), "definition"
| _ -> None, ""
| Vernacexpr.VernacStartTheoremProof (kind, _) -> Some (TheoremKind kind)
| Vernacexpr.VernacDefinition ((_, def), _, _) -> Some (DefinitionType def)
| _ -> None
in
let name = match names with
|[] -> "default"
Expand All @@ -169,7 +195,8 @@ let record_outline document id (ast : Synterp.vernac_control_entry) classif (out
| None -> outline
| Some type_ ->
let range = range_of_id document id in
let element = {id; type_; name; statement; range} in
let statement = string_of_id document id in
let element = {id; type_; name; statement; range; proof=[]} in
element :: outline
end
| VtSideff (names, _) ->
Expand All @@ -179,8 +206,8 @@ let record_outline document id (ast : Synterp.vernac_control_entry) classif (out
| VernacSynterp _ -> None, ""
| VernacSynPure pure ->
match pure with
| Vernacexpr.VernacStartTheoremProof (kind, _) -> Some (TheoremKind kind), "theroem"
| Vernacexpr.VernacDefinition ((_, def), _, _) -> Some (DefinitionType def), "definition"
| Vernacexpr.VernacStartTheoremProof (kind, _) -> Some (TheoremKind kind), string_of_id document id
| Vernacexpr.VernacDefinition ((_, def), _, _) -> Some (DefinitionType def), string_of_id document id
| _ -> None, ""
in
let name = match names with
Expand All @@ -191,11 +218,15 @@ let record_outline document id (ast : Synterp.vernac_control_entry) classif (out
| None -> outline
| Some type_ ->
let range = range_of_id document id in
let element = {id; type_; name; statement; range} in
let element = {id; type_; name; statement; range; proof=[]} in
element :: outline
end
| _ -> outline

let compute_outline ({ sentences_by_end } as document) =
LM.fold (fun _ {id; ast} -> record_outline document id ast.ast ast.classification) sentences_by_end []


let schedule doc = doc.schedule

let raw_document doc = doc.raw_doc
Expand All @@ -217,8 +248,7 @@ let add_sentence parsed parsing_start start stop (ast: parsed_ast) synterp_state
sentences_by_id = SM.add id sentence parsed.sentences_by_id;
schedule;
} in
let outline = record_outline document id ast.ast ast.classification parsed.outline in
{document with outline}, scheduler_state_after
document, scheduler_state_after

let remove_sentence parsed id =
match SM.find_opt id parsed.sentences_by_id with
Expand Down Expand Up @@ -622,7 +652,8 @@ let handle_invalidate {parsed; errors; parsed_comments; stop; top_id; started; p
List.fold_left (fun acc (comment : comment) -> LM.add comment.stop comment acc) comments new_comments
in
let parsed_loc = pos_at_end document in
let parsed_document = {document with parsed_loc; parsing_errors_by_end; comments_by_end} in
let outline = compute_outline document in
let parsed_document = {document with parsed_loc; parsing_errors_by_end; comments_by_end; outline} in
Some {parsed_document; unchanged_id; invalid_ids; previous_document}

let handle_event document = function
Expand Down
9 changes: 8 additions & 1 deletion language-server/dm/document.mli
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,19 @@ type proof_block_type =
| DefinitionType of Decls.definition_object_kind
| Other

type proof_step = {
id: sentence_id;
tactic: string;
range: Range.t;
}

type outline_element = {
id: sentence_id;
name: string;
type_: proof_block_type;
statement: string;
range: Range.t
proof: proof_step list;
range: Range.t;
}

type outline = outline_element list
Expand Down
20 changes: 20 additions & 0 deletions language-server/dm/documentManager.ml
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,26 @@ let observe ~background state id ~should_block_on_error : (state * event Sel.Eve

let reset_to_top st = { st with observe_id = Top }


let get_document_proofs st =
let outline = Document.outline st.document in
let is_theorem Document.{ type_ } =
match type_ with
| TheoremKind _ -> true
| _ -> false
in
let mk_proof_block Document.{statement; proof; range } =
let statement = ProofState.mk_proof_statement statement range in
let last_step = List.hd proof in
let proof = List.rev proof in
let fst_step = List.hd proof in
let range = Range.create ~start:fst_step.range.start ~end_:last_step.range.end_ in
let steps = List.map (fun Document.{tactic; range} -> ProofState.mk_proof_step tactic range) proof in
ProofState.mk_proof_block statement steps range
in
let proofs, _ = List.partition is_theorem outline in
List.map mk_proof_block proofs

let get_document_symbols st =
let outline = Document.outline st.document in
let to_document_symbol elem =
Expand Down
2 changes: 2 additions & 0 deletions language-server/dm/documentManager.mli
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ val get_info_messages : state -> Position.t option -> (DiagnosticSeverity.t * pp

val get_document_symbols : state -> DocumentSymbol.t list

val get_document_proofs : state -> ProofState.proof_block list

val all_diagnostics : state -> Diagnostic.t list
(** all_diagnostics [doc] returns the diagnostics corresponding to the sentences
that have been executed in [doc]. *)
Expand Down
6 changes: 6 additions & 0 deletions language-server/dm/rawDocument.ml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ let word_at_position raw pos : string option =
with _ ->
None

let string_in_range raw start end_ =
try
String.sub raw.text start (end_ - start)
with _ -> (* TODO: ERROR *)
""

let apply_text_edit raw (Range.{start; end_}, editText) =
let start = loc_of_position raw start in
let stop = loc_of_position raw end_ in
Expand Down
1 change: 1 addition & 0 deletions language-server/dm/rawDocument.mli
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ val end_loc : t -> int

val range_of_loc : t -> Loc.t -> Range.t
val word_at_position: t -> Position.t -> string option
val string_in_range: t -> int -> int -> string

(** Applies a text edit, and returns start location *)
val apply_text_edit : t -> text_edit -> t * int
21 changes: 21 additions & 0 deletions language-server/protocol/extProtocol.ml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,22 @@ module Request = struct

end

module DocumentProofsParams = struct

type t = {
textDocument: TextDocumentIdentifier.t
} [@@deriving yojson]

end

module DocumentProofsResult = struct

type t = {
proofs: ProofState.proof_block list;
} [@@deriving yojson]

end

type 'a t =
| Std : 'a Lsp.Client_request.t -> 'a t
| Reset : ResetParams.t -> unit t
Expand All @@ -257,6 +273,7 @@ module Request = struct
| Print : PrintParams.t -> pp t
| Search : SearchParams.t -> unit t
| DocumentState : DocumentStateParams.t -> DocumentStateResult.t t
| DocumentProofs : DocumentProofsParams.t -> DocumentProofsResult.t t

type packed = Pack : 'a t -> packed

Expand Down Expand Up @@ -284,6 +301,9 @@ module Request = struct
| "vscoq/documentState" ->
let+ params = Lsp.Import.Json.message_params params DocumentStateParams.t_of_yojson in
Pack (DocumentState params)
| "vscoq/documentProofs" ->
let+ params = Lsp.Import.Json.message_params params DocumentProofsParams.t_of_yojson in
Pack (DocumentProofs params)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can easily version these custom queries, eg "vscoq/documentProofs/v1" so that we can update the format later without necessarily breaking badly the plugins that use this extension

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So after thinking about it, we make it accessible through a function in the client. If we need new versions it should be easy to keep everything wired on our end when plugins use our extension.

| _ ->
let+ E req = Lsp.Client_request.of_jsonrpc req in
Pack (Std req)
Expand All @@ -298,6 +318,7 @@ module Request = struct
| Print _ -> yojson_of_pp resp
| Search _ -> yojson_of_unit resp
| DocumentState _ -> DocumentStateResult.(yojson_of_t resp)
| DocumentProofs _ -> DocumentProofsResult.(yojson_of_t resp)
| Std req -> Lsp.Client_request.yojson_of_result req resp

end
Expand Down
25 changes: 24 additions & 1 deletion language-server/protocol/proofState.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,26 @@
(**************************************************************************)

open Printing
open Lsp.Types

open Ppx_yojson_conv_lib.Yojson_conv.Primitives

type proof_statement = {
statement: string;
range: Range.t;
} [@@deriving yojson]

type proof_step = {
tactic: string;
range: Range.t;
} [@@deriving yojson]

type proof_block = {
statement: proof_statement;
range: Range.t;
steps: proof_step list;
} [@@deriving yojson]

type goal = {
id: int;
hypotheses: pp list;
Expand Down Expand Up @@ -118,4 +135,10 @@ let get_proof ~previous diff_mode st =
shelvedGoals;
givenUpGoals;
unfocusedGoals;
}
}

let mk_proof_statement statement range = {statement; range}

let mk_proof_step tactic range = {tactic; range}

let mk_proof_block statement steps range = {steps; statement; range}
12 changes: 11 additions & 1 deletion language-server/protocol/proofState.mli
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
(**************************************************************************)
open Settings

type proof_statement [@@deriving yojson]

type proof_step [@@deriving yojson]

type proof_block [@@deriving yojson]

type t [@@deriving yojson]

val get_proof : previous:Vernacstate.t option -> Goals.Diff.Mode.t -> Vernacstate.t -> t option
val get_proof : previous:Vernacstate.t option -> Goals.Diff.Mode.t -> Vernacstate.t -> t option

val mk_proof_statement : string -> Lsp.Types.Range.t -> proof_statement
val mk_proof_step : string -> Lsp.Types.Range.t -> proof_step
val mk_proof_block : proof_statement -> proof_step list -> Lsp.Types.Range.t -> proof_block
Loading
Loading