Getting Started¶
Notation¶
Throughout these docs, keybindings use standard Emacs notation:
| Notation | Meaning |
|---|---|
C- |
Hold Control |
M- |
Hold Alt (or Option on macOS) |
C-c C-d b |
Hold Control, press c, then hold Control and press d, then press b |
C-u |
Universal prefix argument (modifies the next command) |
M-x |
Open the command prompt (run any command by name) |
RET |
Press Enter/Return |
Prerequisites¶
To get the most out of fsharp-ts-mode, you'll want:
- .NET SDK -- for
dotnet fsi,dotnet build, etc. - FsAutoComplete -- the F# language server (auto-installed by
fsharp-ts-eglot)
What Works Out of the Box¶
Once installed, opening any .fs, .fsx, or .fsi
file activates fsharp-ts-mode (or fsharp-ts-signature-mode for .fsi).
The following features work immediately:
- Syntax highlighting via tree-sitter
- Indentation via tree-sitter
- Imenu (symbol index) with fully-qualified names
- Navigation (
C-M-a/C-M-eto move between definitions,C-M-f/C-M-bfor balanced expressions) - Switch between
.fsand.fsifiles (C-c C-a) - Compile (
C-c C-c) with error parsing fordotnet build - .NET API docs lookup at point (
C-c C-d) - Shift region left/right (
C-c >/C-c <) - Format the buffer with Fantomas (
C-c C-f) - Clickable links for URLs and issue references in comments
- project.el integration -- F# solutions and projects are recognized as project roots
- Build directory awareness -- prompts to switch when visiting files under
bin/orobj/
Opt-in Features¶
Some features require loading additional libraries or enabling minor modes. Here's what's available and how to set it up:
F# Interactive (REPL)¶
Adds keybindings for sending code to dotnet fsi. See
REPL Integration for details.
(add-hook 'fsharp-ts-mode-hook #'fsharp-ts-repl-minor-mode)
dotnet CLI commands¶
Adds keybindings for build, test, run, and other dotnet operations. See dotnet CLI for the full command list.
(add-hook 'fsharp-ts-mode-hook #'fsharp-ts-dotnet-mode)
Eglot/LSP with FsAutoComplete¶
Provides completions, diagnostics, type information, and many advanced LSP features. FsAutoComplete is downloaded automatically on first use.
(require 'fsharp-ts-eglot)
(add-hook 'fsharp-ts-mode-hook #'eglot-ensure)
Type signature overlays (LineLens)¶
Shows inferred type signatures as inline overlays after definitions. Requires an active Eglot connection. See LineLens.
(require 'fsharp-ts-lens)
(add-hook 'fsharp-ts-mode-hook #'fsharp-ts-lens-mode)
Documentation info panel¶
Auto-updating side window with rich type documentation. Requires an active Eglot connection. See Documentation Info Panel.
(require 'fsharp-ts-info)
(add-hook 'fsharp-ts-mode-hook #'fsharp-ts-info-mode)
Other opt-in features¶
;; Prettify symbols (-> to →, fun to λ, etc.)
(add-hook 'fsharp-ts-mode-hook #'prettify-symbols-mode)
;; Code folding (Emacs 30+)
(add-hook 'fsharp-ts-mode-hook #'outline-minor-mode)
;; Auto-detect indentation from file contents
(setq fsharp-ts-guess-indent-offset t)
;; Format with Fantomas on every save
(setq fsharp-ts-format-on-save t)
Formatting¶
C-c C-f (fsharp-ts-format-buffer) formats the whole buffer with
Fantomas. Install it with
dotnet tool install -g fantomas, or point fsharp-ts-fantomas-program
at a local install. Fantomas reads the nearest .editorconfig, so your
project's formatting settings are respected. Set fsharp-ts-format-on-save
to t to format automatically before each save.
Recommended Configuration¶
Here's a complete setup that enables all major features:
(use-package fsharp-ts-mode
:ensure t
:hook ((fsharp-ts-mode . fsharp-ts-repl-minor-mode)
(fsharp-ts-mode . fsharp-ts-dotnet-mode)
(fsharp-ts-mode . eglot-ensure)
(fsharp-ts-mode . prettify-symbols-mode))
:config
(require 'fsharp-ts-eglot)
(require 'fsharp-ts-lens)
(require 'fsharp-ts-info)
(add-hook 'fsharp-ts-mode-hook #'fsharp-ts-lens-mode)
(add-hook 'fsharp-ts-mode-hook #'fsharp-ts-info-mode)
(setq fsharp-ts-guess-indent-offset t))
Tip
You don't need everything at once. Start with the base mode, add Eglot when you want LSP features, and add the REPL and dotnet modes as you need them.
Typical Workflow¶
A typical F# editing session looks like this:
- Open a
.fsfile -- fsharp-ts-mode activates automatically - Eglot connects to FsAutoComplete (if configured), giving you completions, diagnostics, and type info
- Edit code with tree-sitter-powered highlighting and indentation
- Use
C-c C-zto send code to the REPL for interactive exploration - Use
C-c C-d bto build,C-c C-d tto run tests (requiresfsharp-ts-dotnet-mode)
Keybinding overlap
When fsharp-ts-dotnet-mode is active, the C-c C-d prefix is
used for dotnet commands, which shadows the base mode's C-c C-d
binding for .NET API docs lookup. Use M-x fsharp-ts-mode-doc-at-point
instead, or bind it to a different key.
Similarly, when fsharp-ts-repl-minor-mode is active, C-c C-c
sends the definition at point to the REPL instead of running compile.
Use M-x compile directly if needed.
Useful Commands¶
Base mode (always active)¶
| Key | Command | Description |
|---|---|---|
C-c C-a |
ff-find-other-file |
Switch between .fs and .fsi |
C-c C-c |
compile |
Run compilation |
C-c C-d |
fsharp-ts-mode-doc-at-point |
Look up symbol in .NET docs |
C-c C-f |
fsharp-ts-format-buffer |
Format the buffer with Fantomas |
C-c > |
fsharp-ts-mode-shift-region-right |
Indent region by one level |
C-c < |
fsharp-ts-mode-shift-region-left |
Dedent region by one level |
See also: Code Navigation for movement commands, REPL Integration for REPL commands, dotnet CLI for build commands.
Documentation lookup¶
| Command | Description |
|---|---|
fsharp-ts-mode-doc-at-point |
Look up symbol at point in .NET API docs |
fsharp-ts-mode-browse-fsharp-docs |
Open the F# documentation home page |
fsharp-ts-mode-search-by-signature |
Search FSDN by type signature (e.g., string -> int) |
Indentation helpers¶
Both shift commands accept a prefix argument to shift by multiple levels
(e.g., C-u 2 C-c > shifts right by 2 levels).
M-x fsharp-ts-mode-guess-indent-offset scans the buffer and sets
fsharp-ts-indent-offset to match the file's convention. Set
fsharp-ts-guess-indent-offset to t to run this automatically on file open.
Debugging¶
fsharp-ts-mode registers F# buffers with dape's
built-in netcoredbg configuration, so once dape and the
netcoredbg adapter are installed,
M-x dape offers the .NET debugger in F# buffers with no extra setup. The
configuration builds and debugs the project's bin/Debug DLL, which works
for F# projects just as it does for C# ones.
Registration happens when a buffer enters the mode, so load dape before opening your F# files (or revert the buffer afterwards).
Known Limitations¶
F# is an indentation-sensitive language -- the tree-sitter grammar needs correct whitespace to parse the code. See the FAQ for details on how this affects editing.
Companion Packages¶
These packages work well alongside fsharp-ts-mode: