From ecd9422d11024201f04874e0dbb6d0dc943c16c3 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Mon, 1 Jul 2024 17:58:21 -0400 Subject: [PATCH] gleam: Add `/gleam-docs` (#13721) This PR adds a `/gleam-docs` slash command to the Gleam extension, which can be used to fetch docs from HexDocs. Release Notes: - N/A --- Cargo.lock | 17 +++++++++-- extensions/gleam/Cargo.toml | 1 + extensions/gleam/extension.toml | 5 ++++ extensions/gleam/src/gleam.rs | 52 +++++++++++++++++++++++++++++++-- 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 206f7e9867..1eea008873 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,7 +388,7 @@ dependencies = [ "fuzzy", "gpui", "heed", - "html_to_markdown", + "html_to_markdown 0.1.0", "http 0.1.0", "indoc", "language", @@ -5237,6 +5237,18 @@ dependencies = [ "regex", ] +[[package]] +name = "html_to_markdown" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e608e8dd0939bfb6b516d96a5919751b835297a02230aecb88d2fc84ebebaa8a" +dependencies = [ + "anyhow", + "html5ever", + "markup5ever_rcdom", + "regex", +] + [[package]] name = "http" version = "0.1.0" @@ -9019,7 +9031,7 @@ dependencies = [ "fuzzy", "gpui", "heed", - "html_to_markdown", + "html_to_markdown 0.1.0", "http 0.1.0", "indexmap 1.9.3", "indoc", @@ -13779,6 +13791,7 @@ dependencies = [ name = "zed_gleam" version = "0.1.3" dependencies = [ + "html_to_markdown 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "zed_extension_api 0.0.7", ] diff --git a/extensions/gleam/Cargo.toml b/extensions/gleam/Cargo.toml index 04e0c40497..089fa9f80e 100644 --- a/extensions/gleam/Cargo.toml +++ b/extensions/gleam/Cargo.toml @@ -13,4 +13,5 @@ path = "src/gleam.rs" crate-type = ["cdylib"] [dependencies] +html_to_markdown = "0.1.0" zed_extension_api = { path = "../../crates/extension_api" } diff --git a/extensions/gleam/extension.toml b/extensions/gleam/extension.toml index 3a290472b2..83e16a5c2c 100644 --- a/extensions/gleam/extension.toml +++ b/extensions/gleam/extension.toml @@ -18,3 +18,8 @@ commit = "8432ffe32ccd360534837256747beb5b1c82fca1" description = "Returns information about the current Gleam project." requires_argument = false tooltip_text = "Insert Gleam project data" + +[slash_commands.gleam-docs] +description = "Returns Gleam docs." +requires_argument = true +tooltip_text = "Insert Gleam docs" diff --git a/extensions/gleam/src/gleam.rs b/extensions/gleam/src/gleam.rs index fd3ddf64ec..2a46454798 100644 --- a/extensions/gleam/src/gleam.rs +++ b/extensions/gleam/src/gleam.rs @@ -1,10 +1,13 @@ +use html_to_markdown::{convert_html_to_markdown, TagHandler}; +use std::cell::RefCell; use std::fs; +use std::rc::Rc; use zed::lsp::CompletionKind; use zed::{ CodeLabel, CodeLabelSpan, LanguageServerId, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, }; -use zed_extension_api::{self as zed, Result}; +use zed_extension_api::{self as zed, fetch, HttpRequest, Result}; struct GleamExtension { cached_binary_path: Option, @@ -164,10 +167,55 @@ impl zed::Extension for GleamExtension { fn run_slash_command( &self, command: SlashCommand, - _argument: Option, + argument: Option, worktree: &zed::Worktree, ) -> Result { match command.name.as_str() { + "gleam-docs" => { + let argument = argument.ok_or_else(|| "missing argument".to_string())?; + + let mut components = argument.split('/'); + let package_name = components + .next() + .ok_or_else(|| "missing package name".to_string())?; + let module_path = components.map(ToString::to_string).collect::>(); + + let response = fetch(&HttpRequest { + url: format!( + "https://hexdocs.pm/{package_name}{maybe_path}", + maybe_path = if !module_path.is_empty() { + format!("/{}.html", module_path.join("/")) + } else { + String::new() + } + ), + })?; + + let mut handlers: Vec = vec![ + Rc::new(RefCell::new( + html_to_markdown::markdown::WebpageChromeRemover, + )), + Rc::new(RefCell::new(html_to_markdown::markdown::ParagraphHandler)), + Rc::new(RefCell::new(html_to_markdown::markdown::HeadingHandler)), + Rc::new(RefCell::new(html_to_markdown::markdown::ListHandler)), + Rc::new(RefCell::new(html_to_markdown::markdown::TableHandler::new())), + Rc::new(RefCell::new(html_to_markdown::markdown::StyledTextHandler)), + ]; + + let markdown = convert_html_to_markdown(response.body.as_bytes(), &mut handlers) + .map_err(|err| format!("failed to convert docs to Markdown {err}"))?; + + let mut text = String::new(); + text.push_str(&markdown); + + Ok(SlashCommandOutput { + sections: vec![SlashCommandOutputSection { + range: (0..text.len()).into(), + label: format!("gleam-docs: {package_name} {}", module_path.join("/")), + }], + text, + }) + } "gleam-project" => { let mut text = String::new(); text.push_str("You are in a Gleam project.\n");