Skip to content
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
acc926b
images and gifs for onboarding
PizieDust Feb 28, 2025
7cabcfd
new onboarding commands
PizieDust Feb 28, 2025
9117b4e
ocaml onboarding sequence of steps
PizieDust Feb 28, 2025
0f2164e
add instructions and new images
PizieDust Mar 11, 2025
83b1346
add link for ocaml survey
PizieDust Mar 11, 2025
33dfc13
better utop screenshot
PizieDust Mar 11, 2025
5bf3191
add changelog
PizieDust Mar 11, 2025
68af690
Update src/extension_commands.ml
PizieDust Mar 14, 2025
5c7e4be
Update src/extension_commands.ml
PizieDust Mar 14, 2025
a0e84bc
Update src/extension_commands.ml
PizieDust Mar 14, 2025
6512210
Update package.json
PizieDust Mar 14, 2025
5f5e0d3
Update package.json
PizieDust Mar 14, 2025
570dc15
Update package.json
PizieDust Mar 14, 2025
42ad0b3
Update package.json
PizieDust Mar 14, 2025
db4bec5
Update package.json
PizieDust Mar 14, 2025
6142976
Update package.json
PizieDust Mar 14, 2025
6363262
Update package.json
PizieDust Mar 14, 2025
a79f64f
Update CHANGELOG.md
PizieDust Mar 14, 2025
354485a
Update package.json
PizieDust Mar 14, 2025
2f5515a
Update package.json
PizieDust Mar 14, 2025
ef7d5c9
Update package.json
PizieDust Mar 14, 2025
c345991
Update package.json
PizieDust Mar 14, 2025
b0c0c35
Update package.json
PizieDust Mar 14, 2025
a4cc07b
better alt descriptions
PizieDust Mar 14, 2025
7dfdeba
fix lint
PizieDust Mar 27, 2025
0b4a255
check each step upon completion of the event
PizieDust Mar 27, 2025
bdc802f
check that opam is installed before proceeding
PizieDust Mar 28, 2025
ee1f2cb
remove unusued value
PizieDust Mar 28, 2025
debb683
changes based on reviews
PizieDust Apr 2, 2025
a54a6e3
explain the different choices in opam init
PizieDust Apr 2, 2025
cf54ef3
Update src/extension_commands.ml
PizieDust Aug 25, 2025
b472f24
update changelog
PizieDust Aug 26, 2025
fe8bf76
update extension commands
PizieDust Aug 26, 2025
615d911
Refactor command executions to use the same terminal instance for con…
PizieDust Aug 26, 2025
0ca33be
Merge branch 'master' into welcome_screen
PizieDust Sep 1, 2025
19d7dce
Merge branch 'master' into welcome_screen
PizieDust Sep 2, 2025
e9090e3
Update package.json
PizieDust Sep 11, 2025
ee84804
Update package.json
PizieDust Sep 11, 2025
41045b3
Update package.json
PizieDust Sep 11, 2025
d4008f2
Update package.json
PizieDust Sep 11, 2025
da40616
Update package.json
PizieDust Sep 11, 2025
6a38ad3
Merge branch 'master' into welcome_screen
PizieDust Sep 11, 2025
b735fa8
Merge branch 'master' into welcome_screen
PizieDust Oct 31, 2025
30b0c79
get the version of opam installed
PizieDust Oct 31, 2025
050e3b3
display the version of opam and ask if user wants to update if outdated
PizieDust Oct 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Add OCaml onboarding welcome screen. (#1737)

## 1.32.3

- Fix utop detection by using `-version` flag instead of `--version` to align
Expand Down
Binary file added assets/ocaml_survey.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/opam_init.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/opam_install.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/opam_switch.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/utop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/vscode-ocaml-commands.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 109 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,114 @@
"test": "vscode-test"
},
"contributes": {
"walkthroughs": [
{
"id": "ocaml-onboarding",
"title": "OCaml: Setup opam dev environment (manual)",
"description": "A guided, terminal based, installation of OCaml and its essential tools with the opam package manager.",
"steps": [
{
"id": "install-opam-windows",
"when": "isWindows",
"title": "Install opam",
"description": "opam is the package manager for OCaml. Installing opam also installs the OCaml compiler. On Windows 10 or 11, install it using Winget:\n\nRun `winget install Git.Git OCaml.opam` in PowerShell.\n\n[Open a terminal and run winget](command:ocaml.install-opam)",
"media": {
"image": "assets/opam_install.jpg",
"altText": "While installing opam, you'll be asked a series of questions: (1) Where should opam be installed? You can press enter and use the default location, unless you wish to install it somehwere else. (2) Sometimes it may request administrator write access, you should enter your password to authorize the installer."
},
"completionEvents": [
"onCommand:ocaml.install-opam"
]
},
{
"id": "install-opam-mac",
"when": "isMac",
"title": "Install opam",
"description": "opam is the package manager for OCaml. Installing opam also installs the OCaml compiler. Install it via opam's official script installer.\n\n[Open a terminal and run the opam install script](command:ocaml.install-opam)",
"media": {
"image": "assets/opam_install.jpg",
"altText": "While installing opam, you'll be asked a series of questions: (1) Where should opam be installed? You can press enter and use the default location, unless you wish to install it somehwere else. (2) Sometimes it may request administrator write access, you should enter your password to authorize the installer."
},
"completionEvents": [
"onCommand:ocaml.install-opam"
]
},
{
"id": "install-opam-linux",
"when": "isLinux",
"title": "Install opam",
"description": "opam is the package manager for OCaml. Installing opam also installs the OCaml compiler. Install it via opam's official script installer.\n\n[Open a terminal and run the opam install script](command:ocaml.install-opam)",
"media": {
"image": "assets/opam_install.jpg",
"altText": "While installing opam, you'll be asked a series of questions: (1) Where should opam be installed? You can press enter and use the default location, unless you wish to install it somehwere else. (2) Sometimes it may request administrator write access, you should enter your password to authorize the installer."
},
"completionEvents": [
"onCommand:ocaml.install-opam"
]
},
{
"id": "init-opam",
"title": "Initialize opam",
"description": "After installing opam, we initialise it so as to prepare your system to use it for managing OCaml packages and compilers.\n\n[Open a terminal and run opam init](command:ocaml.init-opam)",
"media": {
"image": "assets/opam_init.jpg",
"altText": "For the different options: (1) → (recommended) Updates ~/.profile to automatically configure opam for future shell sessions. (2) → Does not update shell configs; requires manual eval $(opam env) after switching. (3) → Allows selecting a different shell (e.g., zsh, fish) for configuration. (4) → Lets you specify a custom config file instead of ~/.profile.5 → No automatic setup; you must manually run eval $(opam env) when needed."
},
"completionEvents": [
"onCommand:ocaml.init-opam"
]
},
{
"id": "activate-opam-switch",
"title": "Activate the opam switch",
"description": "An opam switch is an isolated OCaml environment (like a Python virtual environment) where you can install different OCaml versions and packages. \n\n[Select a switch and activate it](command:ocaml.select-sandbox)",
"media": {
"image": "assets/opam_switch.jpg",
"altText": "An image of tiny ocaml logos arranged in the shape of a camel"
},
"completionEvents": [
"onCommand:ocaml.select-sandbox"
]
},
{
"id": "install-platform-tools",
"title": "Install OCaml Platform Tools",
"description": "Now install essential development tools:\n\n- OCaml LSP server enables editor support for OCaml, odoc generates documentation, camlformat automatically formats OCaml code, utop is an interactive REPL for OCaml and dune is the official OCaml build system.\n\n[Install Platform Tools](command:ocaml.install-ocaml-dev)",
"media": {
"image": "assets/vscode-ocaml-commands.gif",
"altText": "A gif of how to access all commands provided by the OCaml VSCode plugin, which can be accessed by pressing Ctrl+Alt+P and typing ocaml"
},
"completionEvents": [
"onCommand:ocaml.install-ocaml-dev"
]
},
{
"id": "check-installation",
"title": "Check Installation",
"description": "Verify your OCaml installation by running utop. If everything is set up correctly, you should see a prompt like the image on the right. \n\n[Check Installation](command:ocaml.open-utop)",
"media": {
"image": "assets/utop.png",
"altText": "A screenshot showing the output of running utop in a command line"
},
"completionEvents": [
"onCommand:ocaml.open-utop"
]
},
{
"id": "finish-onboarding",
"title": "Congratulations",
"description": "You now have OCaml installed and setup on your computer. Please take a few minutes to answer this short survey.\n\n[OCaml Survey](https://docs.google.com/forms/d/e/1FAIpQLSfGGFZBiw4PF7L0yt2DBX8443G5_7aFL5v6wvo6p5MwL-DW8Q/viewform?usp=pp_url&entry.454013858=Link+in+the+VSCode+plugin)",
"media": {
"image": "assets/ocaml_survey.png",
"altText": "A screenshot of some of the various companies that use OCaml including JaneStreet, Bloomberg, ahrefs, Tezos, Facebook, Microsoft, Docker"
},
"completionEvents": [
"onLink:https://docs.google.com/forms/d/e/1FAIpQLSfGGFZBiw4PF7L0yt2DBX8443G5_7aFL5v6wvo6p5MwL-DW8Q/viewform?usp=pp_url&entry.454013858=Link+in+the+VSCode+plugin"
]
}
]
}
],
"breakpoints": [
{
"language": "ocaml"
Expand Down Expand Up @@ -1372,4 +1480,4 @@
"color": "#f29100",
"theme": "light"
}
}
}
4 changes: 4 additions & 0 deletions src/command_api.ml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ module Internal = struct
let augment_selection_type_verbosity = unit_handle "augment-selection-type-verbosity"
let install_dune_lsp = unit_handle "install-dune-lsp"
let run_dune_pkg_lock = unit_handle "run_dune_pkg_lock"
let install_opam = unit_handle "install-opam"
let init_opam = unit_handle "init-opam"
let install_ocaml_dev = unit_handle "install-ocaml-dev"
let open_utop = unit_handle "open-utop"
end

module Vscode = struct
Expand Down
4 changes: 4 additions & 0 deletions src/command_api.mli
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ module Internal : sig
val augment_selection_type_verbosity : (unit, unit) handle
val install_dune_lsp : (unit, unit) handle
val run_dune_pkg_lock : (unit, unit) handle
val install_opam : (unit, unit) handle
val init_opam : (unit, unit) handle
val install_ocaml_dev : (unit, unit) handle
val open_utop : (unit, unit) handle
end

module Vscode : sig
Expand Down
178 changes: 178 additions & 0 deletions src/extension_commands.ml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,184 @@ let _switch_impl_intf =
command Command_api.Internal.switch_impl_intf callback
;;

let walkthrough_terminal_instance = ref None

let walkthrough_terminal instance =
match !walkthrough_terminal_instance with
| Some t -> t
| None ->
let t =
Terminal_sandbox.create
~name:"OCaml Platform Walkthrough"
(Extension_instance.sandbox instance)
in
walkthrough_terminal_instance := Some t;
t
;;

let _install_opam =
let callback (instance : Extension_instance.t) () =
let process_installation () =
let open Promise.Syntax in
let* opam = Opam.make () in
match opam with
| None ->
let options =
ProgressOptions.create
~location:(`ProgressLocation Notification)
~title:"Installing opam package manager"
~cancellable:false
()
in
let task ~progress:_ ~token:_ =
let+ result =
match Platform.t with
| Win32 ->
let _ =
let terminal =
Extension_instance.sandbox instance |> Terminal_sandbox.create
in
let _ = Terminal_sandbox.show ~preserveFocus:true terminal in
Terminal_sandbox.send terminal "winget install Git.Git OCaml.opam"
in
Ok () |> Promise.return
| Darwin | Linux | Other ->
let open Promise.Result.Syntax in
let+ _ =
let _ =
let terminal = walkthrough_terminal instance in
let _ = Terminal_sandbox.show ~preserveFocus:true terminal in
Terminal_sandbox.send
terminal
"bash -c \"sh <(curl -fsSL https://opam.ocaml.org/install.sh)\""
in
Comment on lines +297 to +301
Copy link
Member

Choose a reason for hiding this comment

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

For people who are on Windows and use WSL2 without having set up their DNS specifically, this will fail, right? Do you have an idea of how the walk-through could catch and handle a DNS-related failure here, @PizieDust ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes indeed, without setting up DNS this step will certainly fail. Usually we just return whatever error vscode gives

Ok () |> Promise.return
in
()
in
match result with
| Ok () -> Ojs.null
| Error err ->
show_message `Error "An error occured while installing opam %s" err;
Ojs.null
in
let+ _ = Vscode.Window.withProgress (module Ojs) ~options ~task in
()
| Some _ -> show_message `Info "Opam is already installed!" |> Promise.return
in
let (_ : unit Promise.t) = process_installation () in
()
in
command Command_api.Internal.install_opam callback
;;

let _init_opam =
let callback (instance : Extension_instance.t) () =
let options =
ProgressOptions.create
~location:(`ProgressLocation Notification)
~title:"Initialising opam"
~cancellable:false
()
in
let task ~progress:_ ~token:_ =
let open Promise.Syntax in
let+ result =
let open Promise.Result.Syntax in
let+ _ =
let _ =
let terminal = walkthrough_terminal instance in
let _ = Terminal_sandbox.show ~preserveFocus:true terminal in
Terminal_sandbox.send terminal "opam init"
in
Ok () |> Promise.return
in
()
in
match result with
| Ok () -> Ojs.null
| Error err ->
show_message `Error "An error occured while initializing opam %s" err;
Ojs.null
in
let _ = Vscode.Window.withProgress (module Ojs) ~options ~task in
()
in
command Command_api.Internal.init_opam callback
;;

let _install_ocaml_dev =
let callback (instance : Extension_instance.t) () =
let options =
ProgressOptions.create
~location:(`ProgressLocation Notification)
~title:"Installing development packages"
~cancellable:false
()
in
let task ~progress:_ ~token:_ =
let open Promise.Syntax in
let+ result =
let open Promise.Result.Syntax in
let+ _ =
let _ =
let terminal = walkthrough_terminal instance in
let _ = Terminal_sandbox.show ~preserveFocus:true terminal in
Terminal_sandbox.send
terminal
"opam install ocaml-lsp-server odoc ocamlformat utop"
in
Ok () |> Promise.return
in
()
in
match result with
| Ok () -> Ojs.null
| Error err ->
show_message `Error "An error occured while installing packages %s" err;
Ojs.null
in
let _ = Vscode.Window.withProgress (module Ojs) ~options ~task in
()
in
command Command_api.Internal.install_ocaml_dev callback
;;

let _open_utop =
let callback (instance : Extension_instance.t) () =
let options =
ProgressOptions.create
~location:(`ProgressLocation Notification)
~title:"Launching utop"
~cancellable:false
()
in
let task ~progress:_ ~token:_ =
let open Promise.Syntax in
let+ result =
let open Promise.Result.Syntax in
let+ _ =
let _ =
let terminal = walkthrough_terminal instance in
let _ = Terminal_sandbox.show ~preserveFocus:true terminal in
Terminal_sandbox.send terminal "opam exec -- utop"
in
Ok () |> Promise.return
in
()
in
match result with
| Ok () -> Ojs.null
| Error err ->
show_message `Error "An error occured while opening utop %s" err;
Ojs.null
in
let _ = Vscode.Window.withProgress (module Ojs) ~options ~task in
()
in
command Command_api.Internal.open_utop callback
;;

let _open_current_dune_file =
let callback (_ : Extension_instance.t) () =
match Vscode.Window.activeTextEditor () with
Expand Down