gleam: Clean up slash commands in preparation for release (#16232)

Marshall Bowers created

This PR cleans up the slash command functionality in preparation for an
upcoming release:

- Removed arguments to `/gleam-project` that were just used as an
example
- Removed `/gleam-docs` in favor of `/docs` with the `gleam-hexdocs`
provider
- Pulled a list of all Gleam packages to use as suggestions

Release Notes:

- N/A

Change summary

extensions/gleam/extension.toml |   5 
extensions/gleam/packages.txt   | 581 +++++++++++++++++++++++++++++++++++
extensions/gleam/src/gleam.rs   |  93 ----
3 files changed, 597 insertions(+), 82 deletions(-)

Detailed changes

extensions/gleam/extension.toml 🔗

@@ -19,9 +19,4 @@ 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"
-
 [indexed_docs_providers.gleam-hexdocs]

extensions/gleam/packages.txt 🔗

@@ -0,0 +1,581 @@
+# The list of Gleam packages.
+# Sourced from `https://packages.gleam.run/packages.sqlite`.
+act
+adglent
+ag_html
+aham
+akaridb
+alanttest1
+alpaca
+amf0
+amnesiac
+antigone
+apollo
+aragorn2
+arcana_signals
+arctic
+argamak
+argus
+argv
+ask
+asterix
+atomic_array
+aws4_request
+bare_package1
+bare_package_one
+bare_package_two
+based
+based_pg
+based_sqlite
+beecrypt
+bidict
+bigben
+bigi
+binary_search
+birdie
+birl
+biscotto
+bison
+blah
+blask
+bliss
+bravo
+bungle
+bytesize
+cactus
+cake
+carpenter
+catppuccin
+cave3dplus
+cgi
+chatbot
+check_maybe_div_by_zero
+chip
+chomp
+chrobot
+chromatic
+classify
+cleam
+collatz
+colored
+colours
+comet
+commonmark
+conllu
+context_fp_gleam
+conversation
+cors_builder
+cosepo
+cosmos
+counter
+crabbucket_pgo
+crabbucket_redis
+crossbar
+css_select
+cymbal
+dahlia
+dbots
+decepticon
+decipher
+decode
+dedent
+defangle
+defer_g
+delay
+dew
+dig
+discord_gleam
+domu
+dot_env
+dotenv_gleam
+dove
+ecoji
+edit_distance
+efetch
+email
+embeds
+emel
+envoy
+esgleam
+espresso
+espresso_pgo_wrapper
+eval
+event_hub
+eventsourcing
+eventsourcing_postgres
+eventsourcing_sqlite
+exception
+exercism_test_runner
+facet
+facquest
+falala
+falcon
+feather
+fetch_event
+ffmpeg
+fibo
+file_streams
+filepath
+filespy
+finch_gleam
+first_gleam_publish_package
+flash
+fluoresce
+fmglee
+fmt
+for_the_crows
+form_coder
+formal
+fp
+fp2
+fp2_gleam
+fp_gl
+fresnel
+fswalk
+functx
+funtil
+gacache
+galant
+gap
+garnet_tool
+gary
+gbase32_clockwork
+gcalc
+gchess
+gemqtt
+gen_core_erlang
+gen_gleam
+geny
+germinal
+ggleam
+gild
+gild_frontend
+gip
+gjwt
+gl
+glacier
+glacier_gleeunit
+gladvent
+glailglind
+glam
+glame
+glaml
+glance
+glance_printer
+glanoid
+glare
+glatch
+glats
+glatus
+glcode
+gleaf
+gleam
+gleam_bbmustache
+gleam_bitwise
+gleam_bson
+gleam_community_ansi
+gleam_community_colour
+gleam_community_maths
+gleam_community_path
+gleam_cors
+gleam_cowboy
+gleam_cowboy_websockets
+gleam_crypto
+gleam_deno
+gleam_dotenv
+gleam_elli
+gleam_email
+gleam_erlang
+gleam_erlexec
+gleam_fetch
+gleam_gun
+gleam_hackney
+gleam_hexpm
+gleam_html
+gleam_http
+gleam_httpc
+gleam_javascript
+gleam_json
+gleam_module_javascript_test
+gleam_mongo
+gleam_nodejs
+gleam_os_mon
+gleam_otp
+gleam_package_interface
+gleam_pgo
+gleam_qs
+gleam_sendgrid
+gleam_stats
+gleam_stdlib
+gleam_synapses
+gleam_tailwind
+gleam_tcp
+gleam_test
+gleam_toml
+gleam_xml
+gleam_yaml
+gleam_zlists
+gleambox
+gleamix
+gleamql
+gleamsver
+gleamy_bench
+gleamy_structures
+gleamyshell
+gleanix
+glearray
+gleastsq
+gleative
+gleb128
+glector
+gledis
+gledo
+gleebor
+gleenix
+gleepl
+gleescript
+gleesend
+gleeunit
+gleez
+gleither
+glemini
+glemo
+glemplate
+glemtext
+glen
+glen_node
+glency
+glentities
+glenv
+glenvy
+glerd
+glerd_json
+glerd_valid
+glerm
+gleroglero
+glesha
+glesha2
+glevatar
+glevenshtein
+glex
+glexec
+glexer
+glexif
+glib
+gliberapay
+glibsql
+gliew
+glimiter
+glimmer
+glimt
+gling
+glint
+glisbn
+glisdigit
+glisten
+glistix_gleeunit
+glistix_nix
+glitch
+glitter
+glittr
+glitzer
+gliua
+globe
+glog
+glome
+gloml
+glomp
+gloom
+glormat
+gloss
+glotel
+glove
+glow
+glow_auth
+glubs
+glubsub
+glucose
+glue
+gluid
+gluon
+gluple
+glv8
+glx
+glychee
+glyph
+glyph_codegen
+glzoneinfo
+gmysql
+go_over
+gopenai
+gpsd_json
+gpxb
+grammy
+gramps
+graph
+grille_pain
+gripe
+gserde
+gstripe
+gsv
+gtempo
+gts
+gtui
+gu
+gwitch
+gwr
+gwt
+gxid
+gzlib
+halo
+handles
+hardcache
+hello_joe
+howdy
+howdy_authentication_cookies
+howdy_uuid
+htmb
+htmgrrrl
+html_components
+html_dsl
+html_lustre_converter
+html_parser
+htmz
+httpp
+hug
+humanise
+hyphenation
+ids
+ieee_float
+illustrious
+immutable_lru
+integer_complexity
+ior
+iox
+iso_8859
+ivy
+jackson
+jasper
+javascript_dom_parser
+jbs
+jot
+json_canvas
+juno
+justin
+keccak_gleam
+kick
+kielet
+kirala_bbmarkdown
+kirala_l4u
+kirala_markdown
+kreator
+libsql
+lite_fs
+logging
+lotta
+lumi
+lustre
+lustre_animation
+lustre_carousel
+lustre_dev_tools
+lustre_hash_state
+lustre_http
+lustre_hx
+lustre_limiter
+lustre_routed
+lustre_ssg
+lustre_transition
+lustre_ui
+lustre_virtual_list
+lustre_websocket
+lzf_gleam
+marceau
+mat
+meadow
+melon
+midas
+migrant
+mineflayer
+minigen
+mist
+mockth
+modem
+monies
+morse_code_translator
+mote
+mug
+mumu
+mungo
+nakai
+nanoworker
+nbeet
+nerf
+nessie
+nessie_cluster
+ngs
+nibble
+nimiq_gleam
+node_socket_client
+node_tags
+non_empty_list
+novdom
+novdom_dev_tools
+novdom_testing
+observatory
+open_color
+openfeature
+opt_args_with_defs_for_gleam
+oteap
+outcome
+outil
+owoify_gleam
+p5js_gleam
+palindrome
+panel
+parallel_map
+parser_gleam
+party
+parz
+pb_lite
+pears
+peggy
+phonetic_gleam
+phony
+phosphor_lustre
+pickle
+pika_id
+pine
+pink
+plex_pin_auth
+plinth
+plunk
+pngleam
+pojo
+pona
+postgresql_protocol
+pprint
+prequel
+pretty_diff
+priorityq
+prng
+process_groups
+process_waiter
+processgroups
+promgleam
+psg
+puddle
+punycode
+qcheck
+qcheck_gleeunit_utils
+qs
+queryb
+question
+rad
+rada
+radiate
+radish
+radish_fork
+ramble
+ranged_int
+ranger
+rank
+react_gleam
+reactive_signal
+ream
+recursive
+redraw
+redraw_dom
+ref
+rememo
+remote_data
+render_md
+repeatedly
+rizzo
+runetracer
+scaffold_gleam
+scriptorium
+sequin
+shakespeare
+shamir
+sheen
+shellout
+shimmer
+showtime
+signal
+signal_pgo
+simple_pubsub
+simplifile
+singularity
+sketch
+sketch_css
+sketch_lustre
+slackin
+snag
+snowgleam
+sol
+sparkle
+spinner
+sprinkle
+sprocket
+sqlight
+squirrel
+stacky
+staff_ai
+starmap
+startest
+stdin
+stego
+stoiridh_version
+storch
+stratus
+string_format
+sturnidae
+sunny
+surreal_gleam
+survey
+swen_jwt
+systemd_status
+tardis
+tcpea
+telega
+temporary
+term_size
+testbldr
+testcontainers_gleam
+the_stars
+tinyroute
+tom
+tote
+translate
+transparent_http
+trie_again
+trust
+tubes
+tulip
+tupler
+typed_headers
+valid
+validate_monadic
+varasto
+vindaloo
+vleam
+wasmify
+weapp
+webls
+webmidi
+wechat_dev_tools
+wemote
+wimp
+wink
+wisp
+wisp_flash
+wolf
+worm
+wp_tables
+xmb
+xmleam
+xmlm
+ygleam
+youid
+zeptomail
+zip_list

extensions/gleam/src/gleam.rs 🔗

@@ -1,16 +1,14 @@
 mod hexdocs;
 
-use std::{fs, io};
-use zed::http_client::{HttpMethod, HttpRequest, RedirectPolicy};
+use std::fs;
+use std::sync::LazyLock;
 use zed::lsp::CompletionKind;
 use zed::{
-    CodeLabel, CodeLabelSpan, KeyValueStore, LanguageServerId, SlashCommand,
-    SlashCommandArgumentCompletion, SlashCommandOutput, SlashCommandOutputSection,
+    CodeLabel, CodeLabelSpan, KeyValueStore, LanguageServerId, SlashCommand, SlashCommandOutput,
+    SlashCommandOutputSection,
 };
 use zed_extension_api::{self as zed, Result};
 
-use crate::hexdocs::convert_hexdocs_to_markdown;
-
 struct GleamExtension {
     cached_binary_path: Option<String>,
 }
@@ -151,78 +149,13 @@ impl zed::Extension for GleamExtension {
         })
     }
 
-    fn complete_slash_command_argument(
-        &self,
-        command: SlashCommand,
-        _arguments: Vec<String>,
-    ) -> Result<Vec<SlashCommandArgumentCompletion>, String> {
-        match command.name.as_str() {
-            "gleam-project" => Ok(vec![
-                SlashCommandArgumentCompletion {
-                    label: "apple".to_string(),
-                    new_text: "Apple".to_string(),
-                    run_command: false,
-                },
-                SlashCommandArgumentCompletion {
-                    label: "banana".to_string(),
-                    new_text: "Banana".to_string(),
-                    run_command: false,
-                },
-                SlashCommandArgumentCompletion {
-                    label: "cherry".to_string(),
-                    new_text: "Cherry".to_string(),
-                    run_command: true,
-                },
-            ]),
-            _ => Ok(Vec::new()),
-        }
-    }
-
     fn run_slash_command(
         &self,
         command: SlashCommand,
-        args: Vec<String>,
+        _args: Vec<String>,
         worktree: Option<&zed::Worktree>,
     ) -> Result<SlashCommandOutput, String> {
         match command.name.as_str() {
-            "gleam-docs" => {
-                let argument = args.last().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::<Vec<_>>();
-
-                let response = HttpRequest::builder()
-                    .method(HttpMethod::Get)
-                    .url(format!(
-                        "https://hexdocs.pm/{package_name}{maybe_path}",
-                        maybe_path = if !module_path.is_empty() {
-                            format!("/{}.html", module_path.join("/"))
-                        } else {
-                            String::new()
-                        }
-                    ))
-                    .header("User-Agent", "Zed (Gleam Extension)")
-                    .redirect_policy(RedirectPolicy::FollowAll)
-                    .build()?
-                    .fetch()?;
-
-                let (markdown, _modules) =
-                    convert_hexdocs_to_markdown(&mut io::Cursor::new(response.body))?;
-
-                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 worktree = worktree.ok_or_else(|| "no worktree")?;
 
@@ -248,11 +181,17 @@ impl zed::Extension for GleamExtension {
 
     fn suggest_docs_packages(&self, provider: String) -> Result<Vec<String>, String> {
         match provider.as_str() {
-            "gleam-hexdocs" => Ok(vec![
-                "gleam_stdlib".to_string(),
-                "birdie".to_string(),
-                "startest".to_string(),
-            ]),
+            "gleam-hexdocs" => {
+                static GLEAM_PACKAGES: LazyLock<Vec<String>> = LazyLock::new(|| {
+                    include_str!("../packages.txt")
+                        .lines()
+                        .filter(|line| !line.starts_with('#'))
+                        .map(|line| line.trim().to_owned())
+                        .collect()
+                });
+
+                Ok(GLEAM_PACKAGES.clone())
+            }
             _ => Ok(Vec::new()),
         }
     }