diff --git a/CHANGELOG.md b/CHANGELOG.md index 17cbe447a..e76ca8176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - Add way to autocomplete an exhaustive switch statement for identifiers. Example: an identifier that's a variant can have a switch autoinserted matching all variant cases. https://github.com/rescript-lang/rescript-vscode/pull/699 - Support typed expression completion for lowercase (builtin) JSX tags. https://github.com/rescript-lang/rescript-vscode/pull/702 - Support typed expression completion driven by type annotations. https://github.com/rescript-lang/rescript-vscode/pull/711 +- Completion for lowercase JSX elements, treating them like HTML elements. https://github.com/rescript-lang/rescript-vscode/pull/719 #### :nail_care: Polish diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 6cf90cde5..d9f9c04fa 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -211,7 +211,7 @@ let getEnvWithOpens ~scope ~(env : QueryEnv.t) ~package | None -> None | Some env -> ResolvePath.resolvePath ~env ~package ~path)) -let detail name (kind : Completion.kind) = +let kindToDetail name (kind : Completion.kind) = match kind with | Type {decl} -> decl |> Shared.declToString name | Value typ -> typ |> Shared.typeToString @@ -568,11 +568,17 @@ let completionToItem insertText; insertTextFormat; filterText; + detail; } = let item = mkItem ~name ~kind:(Completion.kindToInt kind) - ~deprecated ~detail:(detail name kind) ~docstring + ~deprecated + ~detail: + (match detail with + | None -> kindToDetail name kind + | Some detail -> detail) + ~docstring in if !Cfg.supportsSnippets then {item with sortText; insertText; insertTextFormat; filterText} @@ -1526,3 +1532,16 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover | _ -> [c]) | _ -> [c]) |> List.flatten + | ChtmlElement {prefix} -> + CompletionJsx.htmlElements + |> List.filter_map (fun (elementName, description, deprecated) -> + if Utils.startsWith elementName prefix then + let name = "<" ^ elementName ^ ">" in + Some + (Completion.create name ~kind:(Label name) ~detail:description ~env + ~docstring:[description] ~insertText:elementName + ?deprecated: + (match deprecated with + | true -> Some "true" + | false -> None)) + else None) diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index c917fa91c..e8a66ea0f 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -735,7 +735,11 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = in if jsxCompletable <> None then setResultOpt jsxCompletable else if compName.loc |> Loc.hasPos ~pos:posBeforeCursor then - setResult (Cpath (CPId (compNamePath, Module))) + setResult + (match compNamePath with + | [prefix] when Char.lowercase_ascii prefix.[0] = prefix.[0] -> + ChtmlElement {prefix} + | _ -> Cpath (CPId (compNamePath, Module))) | Pexp_apply ( {pexp_desc = Pexp_ident {txt = Lident "|."}}, [ diff --git a/analysis/src/CompletionJsx.ml b/analysis/src/CompletionJsx.ml index d9cfe4557..d9ff3f489 100644 --- a/analysis/src/CompletionJsx.ml +++ b/analysis/src/CompletionJsx.ml @@ -487,6 +487,213 @@ let domLabels = ("suppressContentEditableWarning", bool); ] +(* List and explanations taken from + https://www.tutorialrepublic.com/html-reference/html5-tags.php. *) +let htmlElements = + [ + ("a", "Defines a hyperlink.", false); + ("abbr", "Defines an abbreviated form of a longer word or phrase.", false); + ("acronym", "Defines an acronym. Use instead.", true); + ("address", "Specifies the author's contact information.", false); + ( "applet", + "Embeds a Java applet (mini Java applications) on the page. Use \ + instead.", + true ); + ("area", "Defines a specific area within an image map.", false); + ("article", "Defines an article.", false); + ("aside", "Defines some content loosely related to the page content.", false); + ("audio", "Embeds a sound, or an audio stream in an HTML document.", false); + ("b", "Displays text in a bold style.", false); + ("base", "Defines the base URL for all relative URLs in a document.", false); + ("basefont", "Specifies the base font for a page. Use CSS instead.", true); + ( "bdi", + "Represents text that is isolated from its surrounding for the purposes \ + of bidirectional text formatting.", + false ); + ("bdo", "Overrides the current text direction.", false); + ("big", "Displays text in a large size. Use CSS instead.", true); + ( "blockquote", + "Represents a section that is quoted from another source.", + false ); + ("body", "Defines the document's body.", false); + ("br", "Produces a single line break.", false); + ("button", "Creates a clickable button.", false); + ( "canvas", + "Defines a region in the document, which can be used to draw graphics on \ + the fly via scripting (usually JavaScript).", + false ); + ("caption", "Defines the caption or title of the table.", false); + ("center", "Align contents in the center. Use CSS instead.", true); + ("cite", "Indicates a citation or reference to another source.", false); + ("code", "Specifies text as computer code.", false); + ( "col", + "Defines attribute values for one or more columns in a table.", + false ); + ("colgroup", "Specifies attributes for multiple columns in a table.", false); + ( "data", + "Links a piece of content with a machine-readable translation.", + false ); + ( "datalist", + "Represents a set of pre-defined options for an element.", + false ); + ( "dd", + "Specifies a description, or value for the term (
) in a description \ + list (
).", + false ); + ("del", "Represents text that has been deleted from the document.", false); + ( "details", + "Represents a widget from which the user can obtain additional \ + information or controls on-demand.", + false ); + ("dfn", "Specifies a definition.", false); + ("dialog", "Defines a dialog box or subwindow.", false); + ("dir", "Defines a directory list. Use
    instead.", true); + ("div", "Specifies a division or a section in a document.", false); + ("dl", "Defines a description list.", false); + ("dt", "Defines a term (an item) in a description list.", false); + ("em", "Defines emphasized text.", false); + ( "embed", + "Embeds external application, typically multimedia content like audio or \ + video into an HTML document.", + false ); + ("fieldset", "Specifies a set of related form fields.", false); + ("figcaption", "Defines a caption or legend for a figure.", false); + ("figure", "Represents a figure illustrated as part of the document.", false); + ("font", "Defines font, color, and size for text. Use CSS instead.", true); + ("footer", "Represents the footer of a document or a section.", false); + ("form", "Defines an HTML form for user input.", false); + ("frame", "Defines a single frame within a frameset.", true); + ("frameset", "Defines a collection of frames or other frameset.", true); + ( "head", + "Defines the head portion of the document that contains information \ + about the document such as title.", + false ); + ("header", "Represents the header of a document or a section.", false); + ("hgroup", "Defines a group of headings.", false); + ("h1", "Defines HTML headings.", false); + ("h2", "Defines HTML headings.", false); + ("h3", "Defines HTML headings.", false); + ("h4", "Defines HTML headings.", false); + ("h5", "Defines HTML headings.", false); + ("h6", "Defines HTML headings.", false); + ("hr", "Produce a horizontal line.", false); + ("html", "Defines the root of an HTML document.", false); + ("i", "Displays text in an italic style.", false); + ("iframe", "Displays a URL in an inline frame.", false); + ("img", "Represents an image.", false); + ("input", "Defines an input control.", false); + ( "ins", + "Defines a block of text that has been inserted into a document.", + false ); + ("kbd", "Specifies text as keyboard input.", false); + ( "keygen", + "Represents a control for generating a public-private key pair.", + false ); + ("label", "Defines a label for an control.", false); + ("legend", "Defines a caption for a
    element.", false); + ("li", "Defines a list item.", false); + ( "link", + "Defines the relationship between the current document and an external \ + resource.", + false ); + ("main", "Represents the main or dominant content of the document.", false); + ("map", "Defines a client-side image-map.", false); + ("mark", "Represents text highlighted for reference purposes.", false); + ("menu", "Represents a list of commands.", false); + ( "menuitem", + "Defines a list (or menuitem) of commands that a user can perform.", + false ); + ("meta", "Provides structured metadata about the document content.", false); + ("meter", "Represents a scalar measurement within a known range.", false); + ("nav", "Defines a section of navigation links.", false); + ( "noframes", + "Defines an alternate content that displays in browsers that do not \ + support frames.", + true ); + ( "noscript", + "Defines alternative content to display when the browser doesn't support \ + scripting.", + false ); + ("object", "Defines an embedded object.", false); + ("ol", "Defines an ordered list.", false); + ( "optgroup", + "Defines a group of related options in a selection list.", + false ); + ("option", "Defines an option in a selection list.", false); + ("output", "Represents the result of a calculation.", false); + ("p", "Defines a paragraph.", false); + ("param", "Defines a parameter for an object or applet element.", false); + ("picture", "Defines a container for multiple image sources.", false); + ("pre", "Defines a block of preformatted text.", false); + ("progress", "Represents the completion progress of a task.", false); + ("q", "Defines a short inline quotation.", false); + ( "rp", + "Provides fall-back parenthesis for browsers that that don't support \ + ruby annotations.", + false ); + ( "rt", + "Defines the pronunciation of character presented in a ruby annotations.", + false ); + ("ruby", "Represents a ruby annotation.", false); + ( "s", + "Represents contents that are no longer accurate or no longer relevant.", + false ); + ("samp", "Specifies text as sample output from a computer program.", false); + ( "script", + "Places script in the document for client-side processing.", + false ); + ( "section", + "Defines a section of a document, such as header, footer etc.", + false ); + ("select", "Defines a selection list within a form.", false); + ("small", "Displays text in a smaller size.", false); + ( "source", + "Defines alternative media resources for the media elements like