diff --git a/bin/httui-lsp/httui_lsp.ml b/bin/httui-lsp/httui_lsp.ml index 7b8508f..94fd7ee 100644 --- a/bin/httui-lsp/httui_lsp.ml +++ b/bin/httui-lsp/httui_lsp.ml @@ -139,7 +139,7 @@ let compute_legend ~announced_types ~announced_modifiers = legend_modifiers := List.filter (fun m -> List.mem m announced_modifiers) - [ "declaration"; "unresolved" ] + [ "declaration"; "unresolved"; "secret" ] let type_index (kind : Httui_lang.Semantic_tokens.kind) = let name = @@ -176,6 +176,7 @@ let modifier_bits (t : Httui_lang.Semantic_tokens.t) = let active = (m = "declaration" && t.declaration) || (m = "unresolved" && t.unresolved) + || (m = "secret" && t.secret) in if active then bits lor (1 lsl i) else bits) 0 @@ -322,9 +323,10 @@ let encode_tokens text tokens = in Array.of_list data -let compute_token_data text = +let compute_token_data ~env_keys text = encode_tokens text - (Httui_lang.Semantic_tokens.of_blocks (Httui_lang.Fence_scanner.scan text)) + (Httui_lang.Semantic_tokens.of_blocks ~env_keys + (Httui_lang.Fence_scanner.scan text)) (* Last full result per document, for delta requests: uri -> (resultId, data). Monotonic ids keep delta bookkeeping trivial. *) @@ -364,7 +366,10 @@ let diff_tokens old_ new_ = let on_semantic_tokens (r : Jsonrpc.Request.t) = let p = T.SemanticTokensParams.t_of_yojson (params_json r.params) in with_doc r.id p.textDocument.uri (fun text -> - let data = compute_token_data text in + let env_keys = + Env_store.keys_for ~file_path:(T.DocumentUri.to_path p.textDocument.uri) + in + let data = compute_token_data ~env_keys text in let result_id = store_tokens p.textDocument.uri data in respond r.id (T.SemanticTokens.yojson_of_t @@ -373,7 +378,10 @@ let on_semantic_tokens (r : Jsonrpc.Request.t) = let on_semantic_tokens_delta (r : Jsonrpc.Request.t) = let p = T.SemanticTokensDeltaParams.t_of_yojson (params_json r.params) in with_doc r.id p.textDocument.uri (fun text -> - let data = compute_token_data text in + let env_keys = + Env_store.keys_for ~file_path:(T.DocumentUri.to_path p.textDocument.uri) + in + let data = compute_token_data ~env_keys text in let uri_s = T.DocumentUri.to_string p.textDocument.uri in match Hashtbl.find_opt token_results uri_s with | Some (prev_id, old_data) when prev_id = p.previousResultId -> diff --git a/lib/semantic_tokens.ml b/lib/semantic_tokens.ml index dc0f816..b4fb55d 100644 --- a/lib/semantic_tokens.ml +++ b/lib/semantic_tokens.ml @@ -20,6 +20,7 @@ type t = { kind : kind; unresolved : bool; (** ref with path whose alias is not in scope *) declaration : bool; (** [alias=...] declaration site in the info string *) + secret : bool; (** env var whose value is keychain-backed (is_secret) *) } let plain ~start_ ~stop_ kind = @@ -29,6 +30,7 @@ let plain ~start_ ~stop_ kind = kind; unresolved = false; declaration = false; + secret = false; } (* Fence tokens for the info string. LSP tokens must not overlap, so the @@ -83,7 +85,7 @@ let http_tokens (b : Block.t) ~ref_spans = subtract_holes ~s:tok.start_ ~e:tok.stop_ ref_spans |> List.map (fun (s, e) -> plain ~start_:s ~stop_:e kind)) -let of_blocks blocks = +let of_blocks ?(env_keys = []) blocks = List.concat (List.mapi (fun i (b : Block.t) -> @@ -100,6 +102,7 @@ let of_blocks blocks = kind = Alias; unresolved = false; declaration = true; + secret = false; }; ] | _ -> [] @@ -128,6 +131,9 @@ let of_blocks blocks = kind = name_kind; unresolved = (is_prev || r.has_path) && not known; declaration = false; + secret = + name_kind = Env_var + && List.assoc_opt r.name env_keys = Some true; } :: List.map (fun (s, e) -> @@ -137,6 +143,7 @@ let of_blocks blocks = kind = Ref_path; unresolved = false; declaration = false; + secret = false; }) r.path_segments) in diff --git a/test/test_httui_lang.ml b/test/test_httui_lang.ml index b599fa7..091eaed 100644 --- a/test/test_httui_lang.ml +++ b/test/test_httui_lang.ml @@ -161,6 +161,20 @@ let () = plus refs in req2: ghost (1 name + 1 segment) + req1 (1 name + 2 segments) + TOKEN (1 name) *) check "token count" (List.length toks = 14); + (* the `secret` modifier marks env-var refs whose key is is_secret *) + check "secret env var ref carries the secret modifier" + (List.exists + (fun (t : Httui_lang.Semantic_tokens.t) -> + t.kind = Httui_lang.Semantic_tokens.Env_var && t.secret) + (Httui_lang.Semantic_tokens.of_blocks + ~env_keys:[ ("TOKEN", true) ] + blocks)); + check "env var ref is not secret without the is_secret flag" + (List.for_all + (fun (t : Httui_lang.Semantic_tokens.t) -> not t.secret) + (Httui_lang.Semantic_tokens.of_blocks + ~env_keys:[ ("TOKEN", false) ] + blocks)); (match toks with | first :: _ -> check "first token is the fence lang"