From 3121fc42499754ad013e6c7932580a1f19956894 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sun, 24 Nov 2019 20:54:00 +0100
Subject: [PATCH 001/147] Travis: Use dotnet core sdk

Full Framework version of FSAC is deprecated:
https://github.com/fsharp/FsAutoComplete/issues/506
---
 .travis.yml | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index c5a38f7..85ccd01 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,19 +22,19 @@ env:
   - EMACS_VERSION=snapshot
 
 before_install:
-  # Add mono repo
   - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-  - echo "deb http://download.mono-project.com/repo/ubuntu stable-trusty main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
-  - travis_retry sudo  apt-get -qq update
-  - travis_retry sudo  apt-get install -y mono-devel 
-  # Configure $PATH: Executables are installed to $HOME/bin
+  - wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
+  - sudo apt-get update
+  - sudo apt-get install apt-transport-https
+  - sudo apt-get update
+  - sudo apt-get install dotnet-sdk-2.2
   - export PATH="$HOME/bin:$PATH"
   # Download the makefile to emacs-travis.mk
   - wget 'https://raw.githubusercontent.com/flycheck/emacs-travis/master/emacs-travis.mk'
   # Install Emacs (according to $EMACS_VERSION) and Cask
   - make -f emacs-travis.mk install_emacs
   - make -f emacs-travis.mk install_cask
-  - travis_retry sudo apt-get install -y fsharp mono-xbuild
+  - travis_retry sudo apt-get install -y fsharp
 
 script:
   - make test

From 8a38cc606ce01d9944c05c5f00f3c65fec47112d Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sun, 24 Nov 2019 21:42:04 +0100
Subject: [PATCH 002/147] Add temporary README.md notes about the migration to
 LSP

---
 README.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/README.md b/README.md
index 28dd963..d0dcada 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,14 @@
+# Current state of this repo
+
+Previous versions of `fsharp-mode` (mis)used a second repository [emacs-fsharp-mode-bin](rneatherway/emacs-fsharp-mode-bin) to distribute `fsautocomplete.exe` and `fsharp-mode` together.
+
+Future versions of `fsharp-mode` on [melpa](https://melpa.org/#/fsharp-mode) will be distributed directly from this repository and the installation of `fsautocomplete.exe` will
+be done by the lsp-client [eglot](https://github.com/joaotavora/eglot) or [lsp-mode](https://github.com/emacs-lsp/lsp-mode).
+
+On my build system all tests (using `eglot`) are passed but on travis and appveyor they fail because the tests now use .net core instead of mono: The .travis.yml configuration must be adapted.
+
+If the tests pass through cleanly, I will change the [melpa recipe](https://melpa.org/#/fsharp-mode) to this repo.
+
 # fsharp-mode
 
 Provides support for the F# language in Emacs. Includes the following features:

From c0a1853800951692bedb620057f76a17bddec483 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Mon, 25 Nov 2019 14:57:09 +0100
Subject: [PATCH 003/147] Travis: Install required feed

---
 .travis.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 85ccd01..f6c69f8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -24,10 +24,11 @@ env:
 before_install:
   - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
   - wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
+  - sudo dpkg -i packages-microsoft-prod.deb
   - sudo apt-get update
   - sudo apt-get install apt-transport-https
   - sudo apt-get update
-  - sudo apt-get install dotnet-sdk-2.2
+  - sudo apt-get install dotnet-sdk-2.1
   - export PATH="$HOME/bin:$PATH"
   # Download the makefile to emacs-travis.mk
   - wget 'https://raw.githubusercontent.com/flycheck/emacs-travis/master/emacs-travis.mk'

From dc0682d55350c19bff556d3cd382365272f25662 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Mon, 25 Nov 2019 15:41:57 +0100
Subject: [PATCH 004/147] Travis: use kelleyk's PPA to install Emacs releases

Update to Ubuntu 18.04 (required for PPA).
---
 .travis.yml | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index f6c69f8..2bd88f9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,7 @@ language: emacs-lisp
 # See https://github.com/travis-ci/travis-ci/issues/9061
 # and https://github.com/moby/moby/issues/22801
 sudo: required
-dist: trusty
+dist: bionic
 cache:
   - directories:
       # Cache stable Emacs binaries (saves 1min per job)
@@ -13,27 +13,28 @@ cache:
 matrix:
   fast_finish: true
   allow_failures:
-    - env: EMACS_VERSION=snapshot
+    - env: EMACS_VERSION=emacs-snapshot
 env:
-  - EMACS_VERSION=25.1
-  - EMACS_VERSION=25.2
-  - EMACS_VERSION=25.3
-  - EMACS_VERSION=26.1
-  - EMACS_VERSION=snapshot
+  - EMACS_VERSION=emacs25
+  - EMACS_VERSION=emacs26
+  - EMACS_VERSION=emacs-snapshot
 
 before_install:
+    # Emacs kelleyk PPA
+  - sudo add-apt-repository -y ppa:kelleyk/emacs
+  - sudo apt-get update
+  - sudo apt install $EMACS_VERSION
   - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-  - wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
+  - wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
   - sudo dpkg -i packages-microsoft-prod.deb
   - sudo apt-get update
   - sudo apt-get install apt-transport-https
-  - sudo apt-get update
   - sudo apt-get install dotnet-sdk-2.1
   - export PATH="$HOME/bin:$PATH"
+  - export EMACS=$EMACS_VERSION
   # Download the makefile to emacs-travis.mk
   - wget 'https://raw.githubusercontent.com/flycheck/emacs-travis/master/emacs-travis.mk'
   # Install Emacs (according to $EMACS_VERSION) and Cask
-  - make -f emacs-travis.mk install_emacs
   - make -f emacs-travis.mk install_cask
   - travis_retry sudo apt-get install -y fsharp
 

From b619280690628df8a53f689f1e2acf8f76251755 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Mon, 25 Nov 2019 18:59:28 +0100
Subject: [PATCH 005/147] Travis: Increase eglot connect timeout

---
 test/integration-tests.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 51c2561..90c8810 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -34,7 +34,7 @@
     (expect (file-exists-p  (eglot-fsharp--path-to-server)) :to-be t))
   (it "is enabled on F# Files"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
-      (eglot--tests-connect 10)
+      (eglot--tests-connect 30)
       (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
   (it "provides completion"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
@@ -45,7 +45,7 @@
       (delete-char -3)
       ;; ERROR in fsautocomplet.exe?  Should block instead of "no type check results"
       (eglot--sniffing (:server-notifications s-notifs)
-        (eglot--wait-for (s-notifs 10)
+        (eglot--wait-for (s-notifs 90)
             (&key _id method &allow-other-keys)
           (string= method "textDocument/publishDiagnostics")))
       (completion-at-point)

From 4b914160521bbccbe901933469035cdb226f2f3e Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Tue, 26 Nov 2019 12:44:54 +0100
Subject: [PATCH 006/147] Travis: Use emacs-nox varient

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 2bd88f9..0f9dbf5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,7 +23,7 @@ before_install:
     # Emacs kelleyk PPA
   - sudo add-apt-repository -y ppa:kelleyk/emacs
   - sudo apt-get update
-  - sudo apt install $EMACS_VERSION
+  - sudo apt install $EMACS_VERSION-nox
   - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
   - wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
   - sudo dpkg -i packages-microsoft-prod.deb

From 7380f152b580987c1fe2aadd856ff71137089044 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Tue, 26 Nov 2019 12:45:33 +0100
Subject: [PATCH 007/147] Ensure projects for integration tests are restored

---
 Makefile | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index e504a86..c9045c8 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,10 @@ build: elpa version
 version:
 	$(EMACS) --version
 
-test: version build test/eglot-tests.el
+test/Test1/project.assets.json:
+	dotnet restore test/Test1
+
+test: version build test/eglot-tests.el test/Test1/project.assets.json
 	$(CASK) exec buttercup -L . -L ./test
 
 clean:

From 0b1b649c18be1804d28355fda8db6626decc6836 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Tue, 26 Nov 2019 12:45:54 +0100
Subject: [PATCH 008/147] Travis: Use dotnet 2.1 LTS release

---
 test/Test1/Test1.fsproj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/Test1/Test1.fsproj b/test/Test1/Test1.fsproj
index 2241d61..800a3c1 100644
--- a/test/Test1/Test1.fsproj
+++ b/test/Test1/Test1.fsproj
@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>

From 65c8f6833749fd3b41297572f277f81b0b169431 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Tue, 26 Nov 2019 12:58:41 +0100
Subject: [PATCH 009/147] Travis: Eglot requires Emacs 26

---
 .travis.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 0f9dbf5..082d125 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,7 +15,6 @@ matrix:
   allow_failures:
     - env: EMACS_VERSION=emacs-snapshot
 env:
-  - EMACS_VERSION=emacs25
   - EMACS_VERSION=emacs26
   - EMACS_VERSION=emacs-snapshot
 

From 5e54c15e7c52dd8f7a3ec1ef8f9f34ff98193b83 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 12:42:42 +0100
Subject: [PATCH 010/147] xref: Handle missing definitions gracfully

fsautocomplete doesnt follow LSP spec: :textDocument/definition throws
an error when no definition is found (instead of returning an empty
result).
---
 eglot-fsharp.el | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 4cc4485..ca6b86c 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -107,6 +107,18 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   "Passes through required FsAutoComplete initialization options."
   '(:automaticWorkspaceInit t))
 
+;; FIXME: this should be fixed in FsAutocomplete
+(cl-defmethod xref-backend-definitions :around ((type symbol) _identifier)
+  "FsAutoComplete breaks spec and and returns error instead of empty list."
+  (if (eq major-mode 'fsharp-mode)
+      (condition-case err
+	  (cl-call-next-method)
+	(jsonrpc-error
+	 (when (equal (cadddr err) '(jsonrpc-error-message . "Could not find declaration"))
+	   nil)))
+    (when (cl-next-method-p)
+      (cl-call-next-method))))
+
 (add-to-list 'eglot-server-programs `(fsharp-mode . eglot-fsharp))
 
 (provide 'eglot-fsharp)

From 12fe240c3e2b80d1d3156b8edaa499edf8e6fbed Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 13:14:52 +0100
Subject: [PATCH 011/147] Use LTS release

---
 .travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.travis.yml b/.travis.yml
index 082d125..67c757a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,6 +28,7 @@ before_install:
   - sudo dpkg -i packages-microsoft-prod.deb
   - sudo apt-get update
   - sudo apt-get install apt-transport-https
+  - sudo apt-get update
   - sudo apt-get install dotnet-sdk-2.1
   - export PATH="$HOME/bin:$PATH"
   - export EMACS=$EMACS_VERSION

From 3845d689e7c4efc610354a713d2de1a0360b9b85 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 13:19:19 +0100
Subject: [PATCH 012/147] Add integration-test for non-existing identifiers

---
 test/integration-tests.el | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 90c8810..0cdb573 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -49,7 +49,17 @@
             (&key _id method &allow-other-keys)
           (string= method "textDocument/publishDiagnostics")))
       (completion-at-point)
-      (expect (looking-back "X\\.func") :to-be t))))
+      (expect (looking-back "X\\.func") :to-be t)))
+  (it "doesn't throw error when definition does not exist"
+      (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+	(goto-char 253)
+	(expect (current-word) :to-equal "printfn") ;sanity check
+	(expect
+	 (condition-case err
+	     (call-interactively #'xref-find-definitions)
+	   (user-error
+	    (cadr err)))
+	 :to-equal "No definitions found for: LSP identifier at point."))))
 
 (provide 'integration-tests)
 ;;; integration-tests.el ends here

From d1f51a2bf61fe930832995f6e504bad9f67af146 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 13:20:55 +0100
Subject: [PATCH 013/147] Fix order of compilation units

---
 test/Test1/Test1.fsproj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/Test1/Test1.fsproj b/test/Test1/Test1.fsproj
index 800a3c1..cfb7619 100644
--- a/test/Test1/Test1.fsproj
+++ b/test/Test1/Test1.fsproj
@@ -6,8 +6,8 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <Compile Include="Program.fs" />
     <Compile Include="FileTwo.fs" />
+    <Compile Include="Program.fs" />
   </ItemGroup>
 
 </Project>

From a549ed14fd1fcf195a7c5a7e274353aaff169c6a Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 13:30:34 +0100
Subject: [PATCH 014/147] Add integration-test for existing identifiers in
 other files

---
 test/integration-tests.el | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 0cdb573..2acf414 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -59,7 +59,13 @@
 	     (call-interactively #'xref-find-definitions)
 	   (user-error
 	    (cadr err)))
-	 :to-equal "No definitions found for: LSP identifier at point."))))
+	 :to-equal "No definitions found for: LSP identifier at point.")))
+  (it "finds definitions in other files of Project"
+      (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+	(goto-char 150)
+	(expect (current-word) :to-equal "NewObjectType") ;sanity check
+	(call-interactively #'xref-find-definitions)
+	(expect (file-name-nondirectory (buffer-file-name)) :to-equal "FileTwo.fs"))))
 
 (provide 'integration-tests)
 ;;; integration-tests.el ends here

From f1a66e579d14ba6478a6e587e8826b9760ae23f0 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 13:36:39 +0100
Subject: [PATCH 015/147] Add flymake integration-test

---
 test/Test1/Test1.fsproj   |  1 +
 test/integration-tests.el | 13 +++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/test/Test1/Test1.fsproj b/test/Test1/Test1.fsproj
index cfb7619..348b5cb 100644
--- a/test/Test1/Test1.fsproj
+++ b/test/Test1/Test1.fsproj
@@ -6,6 +6,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <Compile Include="Error.fs" />
     <Compile Include="FileTwo.fs" />
     <Compile Include="Program.fs" />
   </ItemGroup>
diff --git a/test/integration-tests.el b/test/integration-tests.el
index 2acf414..e807f2a 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -32,6 +32,19 @@
   (it "Can be installed"
     (eglot-fsharp--maybe-install)
     (expect (file-exists-p  (eglot-fsharp--path-to-server)) :to-be t))
+  (it "shows flymake errors"
+    (with-current-buffer (eglot--find-file-noselect "test/Test1/Error.fs")
+      (eglot--tests-connect 10)
+      (search-forward "nonexisting")
+      (flymake-mode t)
+      (flymake-start)
+      (goto-char (point-min))
+      (eglot--sniffing (:server-notifications s-notifs)
+        (eglot--wait-for (s-notifs 10)
+            (&key _id method &allow-other-keys)
+          (string= method "textDocument/publishDiagnostics")))
+      (flymake-goto-next-error 1 '() t)
+      (expect (face-at-point) :to-be 'flymake-error )))
   (it "is enabled on F# Files"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
       (eglot--tests-connect 30)

From 5ee29867342b0b68cc1a269b97ee2f9f16385419 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 13:48:27 +0100
Subject: [PATCH 016/147] DRY: New helper function for LSP events sniffing

---
 test/integration-tests.el | 47 ++++++++++++++++++++-------------------
 1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index e807f2a..c188769 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -28,6 +28,12 @@
 (require 'eglot-fsharp)
 (require 'eglot-tests)
 
+(defun eglot-fsharp--sniff-diagnostics ()
+  (eglot--sniffing (:server-notifications s-notifs)
+    (eglot--wait-for (s-notifs 10)
+	(&key _id method &allow-other-keys)
+      (string= method "textDocument/publishDiagnostics"))))
+
 (describe "F# LSP server"
   (it "Can be installed"
     (eglot-fsharp--maybe-install)
@@ -39,46 +45,41 @@
       (flymake-mode t)
       (flymake-start)
       (goto-char (point-min))
-      (eglot--sniffing (:server-notifications s-notifs)
-        (eglot--wait-for (s-notifs 10)
-            (&key _id method &allow-other-keys)
-          (string= method "textDocument/publishDiagnostics")))
+      (eglot-fsharp--sniff-diagnostics)
       (flymake-goto-next-error 1 '() t)
       (expect (face-at-point) :to-be 'flymake-error )))
   (it "is enabled on F# Files"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
-      (eglot--tests-connect 30)
       (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
   (it "provides completion"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
+      (eglot-fsharp--sniff-diagnostics)
       (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))
   (it "completes function in other modules"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
       (search-forward "X.func")
       (delete-char -3)
       ;; ERROR in fsautocomplet.exe?  Should block instead of "no type check results"
-      (eglot--sniffing (:server-notifications s-notifs)
-        (eglot--wait-for (s-notifs 90)
-            (&key _id method &allow-other-keys)
-          (string= method "textDocument/publishDiagnostics")))
+      (eglot-fsharp--sniff-diagnostics)
       (completion-at-point)
       (expect (looking-back "X\\.func") :to-be t)))
   (it "doesn't throw error when definition does not exist"
-      (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-	(goto-char 253)
-	(expect (current-word) :to-equal "printfn") ;sanity check
-	(expect
-	 (condition-case err
-	     (call-interactively #'xref-find-definitions)
-	   (user-error
-	    (cadr err)))
-	 :to-equal "No definitions found for: LSP identifier at point.")))
+    (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+      (eglot-fsharp--sniff-diagnostics)
+      (goto-char 253)
+      (expect (current-word) :to-equal "printfn") ;sanity check
+      (expect
+       (condition-case err
+	   (call-interactively #'xref-find-definitions)
+	 (user-error
+	  (cadr err)))
+       :to-equal "No definitions found for: LSP identifier at point.")))
   (it "finds definitions in other files of Project"
-      (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-	(goto-char 150)
-	(expect (current-word) :to-equal "NewObjectType") ;sanity check
-	(call-interactively #'xref-find-definitions)
-	(expect (file-name-nondirectory (buffer-file-name)) :to-equal "FileTwo.fs"))))
+    (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+      (goto-char 150)
+      (expect (current-word) :to-equal "NewObjectType") ;sanity check
+      (call-interactively #'xref-find-definitions)
+      (expect (file-name-nondirectory (buffer-file-name)) :to-equal "FileTwo.fs"))))
 
 (provide 'integration-tests)
 ;;; integration-tests.el ends here

From 9984ed689f219e49d5cfb1d11311f6dc47b66fbc Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 14:28:19 +0100
Subject: [PATCH 017/147] Increase LSP-sniffing timeout in integration-tests
 (Travis failures)

---
 test/integration-tests.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index c188769..d3bec19 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -30,7 +30,7 @@
 
 (defun eglot-fsharp--sniff-diagnostics ()
   (eglot--sniffing (:server-notifications s-notifs)
-    (eglot--wait-for (s-notifs 10)
+    (eglot--wait-for (s-notifs 20)
 	(&key _id method &allow-other-keys)
       (string= method "textDocument/publishDiagnostics"))))
 

From d000a8d15582f2ef1612893ef64b389a793e7773 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 14:59:50 +0100
Subject: [PATCH 018/147] Add elisp tracebacks for integration-tests for better
 debugging

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c9045c8..deaa466 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ test/Test1/project.assets.json:
 	dotnet restore test/Test1
 
 test: version build test/eglot-tests.el test/Test1/project.assets.json
-	$(CASK) exec buttercup -L . -L ./test
+	$(CASK) exec buttercup -L . -L ./test --traceback full
 
 clean:
 	rm -f .depend elpa-$(EMACS) $(OBJECTS) $(PKG)-autoloads.el

From 0bf43b4ee8fc3e7dc2d152259564b1d07c8216c5 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 15:34:56 +0100
Subject: [PATCH 019/147] add missing file for integration tests

---
 test/Test1/Error.fs | 4 ++++
 1 file changed, 4 insertions(+)
 create mode 100644 test/Test1/Error.fs

diff --git a/test/Test1/Error.fs b/test/Test1/Error.fs
new file mode 100644
index 0000000..728aa5c
--- /dev/null
+++ b/test/Test1/Error.fs
@@ -0,0 +1,4 @@
+module Error
+
+let x = nonexisting()
+

From 1cf5bce9b8e9dc41b2f48148fe1d0ec54ada285f Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sat, 30 Nov 2019 15:40:01 +0100
Subject: [PATCH 020/147] dotnet 2.1 LTS restore doesn't create
 project.assets.json

---
 Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index deaa466..75a67d8 100644
--- a/Makefile
+++ b/Makefile
@@ -21,10 +21,11 @@ build: elpa version
 version:
 	$(EMACS) --version
 
-test/Test1/project.assets.json:
+test/Test1/restored:
 	dotnet restore test/Test1
+	touch test/Test1/restored
 
-test: version build test/eglot-tests.el test/Test1/project.assets.json
+test: version build test/eglot-tests.el test/Test1/restored
 	$(CASK) exec buttercup -L . -L ./test --traceback full
 
 clean:

From ca1e974e6b53260305a3578690555751bfcec4e1 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sun, 1 Dec 2019 16:53:34 +0100
Subject: [PATCH 021/147] Update README and convert to org-mode

---
 README.md  | 320 -----------------------------------------------------
 README.org | 190 +++++++++++++++++++++++++++++++
 2 files changed, 190 insertions(+), 320 deletions(-)
 delete mode 100644 README.md
 create mode 100644 README.org

diff --git a/README.md b/README.md
deleted file mode 100644
index d0dcada..0000000
--- a/README.md
+++ /dev/null
@@ -1,320 +0,0 @@
-# Current state of this repo
-
-Previous versions of `fsharp-mode` (mis)used a second repository [emacs-fsharp-mode-bin](rneatherway/emacs-fsharp-mode-bin) to distribute `fsautocomplete.exe` and `fsharp-mode` together.
-
-Future versions of `fsharp-mode` on [melpa](https://melpa.org/#/fsharp-mode) will be distributed directly from this repository and the installation of `fsautocomplete.exe` will
-be done by the lsp-client [eglot](https://github.com/joaotavora/eglot) or [lsp-mode](https://github.com/emacs-lsp/lsp-mode).
-
-On my build system all tests (using `eglot`) are passed but on travis and appveyor they fail because the tests now use .net core instead of mono: The .travis.yml configuration must be adapted.
-
-If the tests pass through cleanly, I will change the [melpa recipe](https://melpa.org/#/fsharp-mode) to this repo.
-
-# fsharp-mode
-
-Provides support for the F# language in Emacs. Includes the following features:
-
-- Support for F# Interactive
-- Displays type signatures and tooltips
-- Provides syntax highlighting and indentation.
-- Intellisense support.
-
-The following features are under development:
-
-- Intelligent indentation
-
-Requires Emacs 25.1+, Mono 3.10.X and F# 3.0 or higher. Without F# 3.0 (or higher)
-the background compiler process will not function correctly.
-
-## Build Status
-
-### Travis [![Travis build status](https://travis-ci.org/fsharp/emacs-fsharp-mode.png)](https://travis-ci.org/fsharp/emacs-fsharp-mode)
-
-See [.travis.yml](.travis.yml) for details.
-
-## Installation
-
-### Package
-
-`fsharp-mode` is available on [MELPA](https://melpa.org) and can
-be installed using the built-in package manager.
-
-If you're not already using MELPA, add the following to your init.el:
-
-```lisp
-;;; Initialize MELPA
-(require 'package)
-(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
-(unless package-archive-contents (package-refresh-contents))
-(package-initialize)
-
-;;; Install fsharp-mode
-(unless (package-installed-p 'fsharp-mode)
-  (package-install 'fsharp-mode))
-
-(require 'fsharp-mode)
-```
-
-If you are a user of [use-package](https://github.com/jwiegley/use-package) you can instead do
-
-```lisp
-(use-package fsharp-mode
-  :defer t
-  :ensure t)
-```
-
-All the [Configuration](#Configuration) options listed below can be added as part of the `:config` section on the `use-package` entry. 
-
-### Manual installation
-
-1. Clone this repo and run `make install`:
-    ```
-    git clone git://github.com/fsharp/emacs-fsharp-mode.git
-    cd emacs-fsharp-mode/emacs
-    make test-all # optional
-    make install
-    ```
-
-2. Add the following to your init.el:
-    ```lisp
-    (add-to-list 'load-path "~/.emacs.d/fsharp-mode/")
-    (autoload 'fsharp-mode "fsharp-mode"     "Major mode for editing F# code." t)
-    (add-to-list 'auto-mode-alist '("\\.fs[iylx]?$" . fsharp-mode))
-    ```
-
-Note that if you do not use `make install`, which attempts to download
-the dependencies from MELPA for you, then you must ensure that you have
-installed them yourself. A list can be found in `fsharp-mode-pkg.el`.
-
-If you run into any problems with installation, please check that you
-have Emacs 24 on your PATH using `emacs --version`.
-Note that OSX comes with Emacs 22 by default and installing a .app of
-Emacs 24 will not add it to your PATH. One option is:
-
-`alias emacs='/Applications/Emacs.app/Contents/MacOS/Emacs'`
-
-## Usage
-
-fsharp-mode should launch automatically whenever you open an F#
-buffer. When the intellisense process is running, the following features will be available:
-
-1. Type information for symbol at point will be displayed in the minibuffer.
-2. Errors and warnings will be automatically highlighted, with mouseover
-   text. Jump to the next and previous error using <kbd>M-n</kbd> and <kbd>M-p</kbd>.
-3. To display a tooltip, move the cursor to a symbol and press
-   <kbd>C-c C-t</kbd> (default).
-4. To jump to the definition of a symbol at point, use <kbd>C-c C-d</kbd>.
-5. Completion will be invoked automatically on dot, as in Visual Studio.
-   It may be invoked manually using `fsharp-ac/complete-at-point`,
-   bound by default to <kbd>C-c C-.</kbd>.
-6. To stop the intellisense process for any reason, use <kbd>C-c C-q</kbd>.
-
-### Projects
-
-fsharp-mode offers intellisense for projects using the MSBuild/`.fsproj`
-format. This allows project files to be shared with other developers using
-Visual Studio and Xamarin Studio/Monodevelop. To create a new project file, it
-is recommended that you take an existing project file and modify the list of
-source files. One such project file can be found in the fsharp-mode repository
-[here](https://github.com/fsharp/emacs-fsharp-mode/blob/master/test/Test1/Test1.fsproj). Alternatively
-projects generated via [forge](https://github.com/ionide/Forge) are setup
-with the needed files.
-
-If, on loading a new `.fs` file, a `.fsproj` file is found in the
-current or an enclosing directory, the intellisense process will be
-launched if necessary, and the project loaded. When a project file is
-loaded for the first time, this will be reported in the
-minibuffer. Projects can also be manually loaded using <kbd>C-c
-C-p</kbd>. This may be needed if a project file is in an unusual
-location relative to a source file, or if the project file has been
-modified (for example to add or remove a source file).
-
-### Scripts
-
-F# scripts (`.fsx` files) are standalone, and require no project file. If you wish open a script file and the intellisense process is not yet running, it will be launched automatically.
-
-## Configuration
-
-### Compiler and REPL paths
-
-The F# compiler and interpreter should be set to good defaults for
-your OS as long as the relevant executables can be found on your PATH
-or in other standard locations. If you have a non-standard setup you
-may need to configure these paths manually.
-
-On Windows:
-
-```lisp
-(setq inferior-fsharp-program "\"c:\\Path\To\Fsi.exe\"")
-(setq fsharp-compiler "\"c:\\Path\To\Fsc.exe\"")
-```
-
-On Unix-like systems, you must use the *--readline-* flag to ensure F#
-Interactive will work correctly with Emacs. Typically `fsi` and `fsc` are
-invoked through the shell scripts `fsharpi` and `fsharpc`.
-
-```lisp
-(setq inferior-fsharp-program "path/to/fsharpi --readline-")
-(setq fsharp-compiler "path/to/fsharpc")
-```
-
-### Behavior
-
-There are a few variables you can adjust to change how fsharp-mode behaves:
-
-- `fsharp-ac-use-popup`: Show tooltips using a popup at the cursor
-  position. If set to nil, display the tooltip in a split window.
-
-- `fsharp-doc-idle-delay`: Set the time (in seconds) to wait before
-  showing type information in the minibuffer.
-  
-- `fsharp-ac-intellisense-enabled`: This mode overrides some aspects of
-  auto-complete configuration and runs the background process automatically.
-  Set to nil to prevent this. Note that this will only prevent the background
-  process from being launched in the *future*. If it is already running you
-  will also need to quit it using <kbd>C-c C-q</kbd>.
-
-You might also add `company-sort-prefer-same-case-prefix` to the list
-of company transformers to to prefer exact case sort in completion
-lists:
-
-```lisp
-(add-to-list 'company-transformers 'company-sort-prefer-same-case-prefix)
-```
-
-### Key Bindings
-
-If you are new to Emacs, you might want to use the menu (call
-menu-bar-mode if you don't see it). However, it's usually faster to learn
-a few useful bindings:
-
- Key binding                         | Description
--------------------------------------|----------------------------------------
-<kbd>C-c C-r</kbd>                   | Evaluate region
-<kbd>C-c C-f</kbd>                   | Load current buffer into toplevel
-<kbd>C-c C-e</kbd>                   | Evaluate current toplevel phrase
-<kbd>C-M-x</kbd>                     | Evaluate current toplevel phrase
-<kbd>C-M-h</kbd>                     | Mark current toplevel phrase
-<kbd>C-c C-s</kbd>                   | Show interactive buffer
-<kbd>C-c C-c</kbd>                   | Compile with fsc
-<kbd>C-c x</kbd>                     | Run the executable
-<kbd>C-c C-a</kbd>                   | Open alternate file (.fsi or .fs)
-<kbd>C-c l</kbd>                     | Shift region to left
-<kbd>C-c r</kbd>                     | Shift region to right
-<kbd>C-c &lt;up&gt;</kbd>            | Move cursor to the beginning of the block
-<kbd>C-c C-p</kbd>                   | Load a project for autocompletion and tooltips
-<kbd>C-c C-d</kbd>, <kbd>M-.</kbd>   | Jump to definition of symbol at point
-<kbd>C-c C-b</kbd>, <kbd>M-,</kbd>   | Return to where point was before jump.
-<kbd>C-c C-t</kbd>                   | Request a tooltip for symbol at point
-<kbd>C-c C-q</kbd>                   | Quit current background compiler process
-
-To interrupt the interactive mode, use <kbd>C-c C-c</kbd>. This is useful if your
-code does an infinite loop or a very long computation.
-
-If you want to shift the region by 2 spaces, use: <kbd>M-2 C-c r</kbd>
-
-In the interactive buffer, use <kbd>M-RET</kbd> to send the code without
-explicitly adding the `;;` thing.
-
-For key bindings that will be more familiar to users of Visual Studio, adding
-the following to your `init.el` may be a good start:
-
-```lisp
-(add-hook 'fsharp-mode-hook
- (lambda ()
-   (define-key fsharp-mode-map (kbd "M-RET") 'fsharp-eval-region)
-   (define-key fsharp-mode-map (kbd "C-SPC") 'fsharp-ac/complete-at-point)))
-```
-
-## Editor
-
-In order to change tab size it is possile to put this in emacs profile:
-
-```lisp
-(setq-default fsharp-indent-offset 2)
-```
-
-Because the F# language is sensitive to indentation, you might wan't to highlight indentation:
-
-```lisp
-(add-hook 'fsharp-mode-hook 'highlight-indentation-mode)
-```
-
-## Troubleshooting
-
-`fsharp-mode` is still under development, so you may encounter some issues. Please report them so we can improve things! Either open an issue on [Github](https://github.com/fsharp/emacs-fsharp-mode/) with the label `Emacs`, or email the [mailing list](http://groups.google.com/group/fsharp-opensource).
-
-### `fsharp-ac-debug`
-
-If you set the variable `fsharp-ac-debug` to a non-`nil` value, e.g. `(setq fsharp-ac-debug 0)`, then some debug output will be seen in the buffer `*fsharp-debug*`. Setting `fsharp-ac-debug` to an 1 or 2 will cause a truncated or complete copy of communication between Emacs and the background intellisense process to be logged in `*fsharp-debug*`. This can make things rather slow, but would be useful for bug reports.
-
-### Project file issues
-
-If your project file does not seem to be being parsed correctly, so that you have missing references or other incorrect intellisense results, it is possible to obtain a detailed log of the project file loading process as follows:
-
-* Open the F# file where the problems are visible.
-* Set `fsharp-ac-debug` to 2, for example by `M-: (setq fsharp-ac-debug 2)`.
-* Reload the project file using `C-c C-p`.
-* Attach the detailed log output from your `*Messages*` buffer to a [new issue](https://github.com/fsharp/emacs-fsharp-mode/issues/new).
-
-As an example, the log output will start similarly to:
-
-```
-<full path to>/MyProject.fsproj:
-Loading default tasks for ToolsVersion: 4.0 from /usr/lib/mono/4.5/Microsoft.Common.tasks
-<full path to>/MyProject.fsproj: Importing project
-...
-```
-
-As an alternative, the command line tool responsible can be invoked directly to obtain the same log. Assuming you have installed from MELPA and are running on Linux or OS X, the following should work:
-
-    mono ~/.emacs.d/elpa/fsharp-mode-<date>/bin/FSharp.Compiler.Service.ProjectCrackerTool.exe --text <path to>/MyProject.fsproj true
-
-On Windows the `mono` prefix is not required, and if you have installed using a different method then the files will be in a different location.
-
-### `Error: F# completion process produced malformed JSON.`
-
-This is probably the result of the background intellisense process crashing and printing a stacktrace in plain text. Please report the crash, preferably with how to reproduce, and the contents of the `*fsharp-complete*` buffer.
-
-### `Error: background intellisense process not running.`
-
-You have requested some intellisense information (such as completions or a tooltip), but the background process is not running. The most common cause of this is that a standard `.fs` file is being visited in the current buffer, but a `.fsproj` project file was not found in the same directory. Try loading one with <kbd>C-c C-p</kbd>.
-
-### `Error: this file is not part of the loaded project.`
-
-In this case you have requested intellisense for the visited file, which is a standard `.fs` file *not* included in the current loaded project. Try loading the appropriate project with <kbd>C-c C-p</kbd>.
-
-### `(void-function -any)` or similar
-
-MELPA's use of dates instead of proper version numbers means that the libraries that `fsharp-mode` depends on -- `dash.el` and `s.el` -- may be out of date if you have previously installed them. Try updating all your packages to the latest versions using `M-x package-list-packages U x`.
-
-### Windows completion menu performance
-
-There are some issues with the `pos-tip` library used to display the documentation tooltips for completions. This can cause sluggish performance when scrolling through the list if you try to move up or down just before the tooltip is displayed. We are looking into proper solutions for this with the `pos-tip` maintainer. For now you can work around the issue with `(setq ac-quick-help-prefer-pos-tip nil)`. This will use an alternative method for displaying these tooltips that is faster but uglier.
-
-### Installing from Git
-
-If you installed by cloning the git repository and you are having problems, please sanity check by running `make test-all` in the `emacs` folder.
-
-### Using a different version of FsAutoComplete
-
-Installing with `make install ac_from_src=yes` will build FsAutoComplete from their lastest master commit instead of using their current binary distribution. Build from a specific commit by passing `ac_commit=$COMMIT_HASH`.
-
-## Contributing
-
-This project is maintained by the
-[F# Software Foundation](http://fsharp.org/), with the repository hosted
-on [GitHub](https://github.com/fsharp/emacs-fsharp-mode).
-
-Pull requests are welcome. Please run the test-suite with `make
-test-all` before submitting a pull request.
-
-Maintainers
------------
-
-The maintainers of this repository appointed by the F# Core Engineering Group are:
-
- - [Jürgen Hötzel](https://github.com/juergenhoetzel), [Steffen Forkmann](http://github.com/forki), [Karl Nilsson](http://github.com/kjnilsson) and [Guillermo López-Anglada](http://github.com/guillermooo)
- - The primary maintainer for this repository is [Jürgen Hötzel](https://github.com/juergenhoetzel)
-
-Previous maintainers:
- - [Robin Neatherway](https://github.com/rneatherway)
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..b34b066
--- /dev/null
+++ b/README.org
@@ -0,0 +1,190 @@
+[[http://melpa.org/#/fsharp-mode][file:http://melpa.org/packages/fsharp-mode-badge.svg]]
+[[https://travis-ci.org/fsharp/emacs-fsharp-mode][file:https://travis-ci.org/fsharp/emacs-fsharp-mode.png]]
+* fsharp-mode
+
+Provides support for the F# language in Emacs. Includes the following features:
+
+- Syntax highlighting and indentation
+- Support for F# Interactive
+- Via [[https://github.com/joaotavora/eglot/issues][Eglot]] LSP-client integration:
+  - Displays type signatures and tooltips
+  - Flymake
+  - Completion
+  - Jump to definition [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html][Find Identifier References]] (Xref)
+
+** LSP mode
+Previous versions of =fsharp-mode= (mis)used a second repository [[https://github.com/rneatherway/emacs-fsharp-mode-bin][emacs-fsharp-mode-bin]] to distribute =fsautocomplete.exe= and =fsharp-mode= together.
+
+The current version of =fsharp-mode= installs =fsautocomplete.exe= automatically via  [eglot-fsharp](https://github.com/joaotavora/eglot) (part of this repo) or 
+[lsp-mode](https://github.com/emacs-lsp/lsp-mode) (untested).
+
+=fsharp-mode= is tested with Emacs 26.1+ and NET Core 2.1 (LTS)
+
+** Installation
+
+*** Package (*OUTDATED*)
+
+*Currently the MELPA package is outdated*! ATM it still refers to  [[https://github.com/rneatherway/emacs-fsharp-mode-bin][emacs-fsharp-mode-bin]]!
+
+=fsharp-mode= is available on [MELPA](https://melpa.org) and can
+be installed using the built-in package manager.
+
+If you're not already using MELPA, add the following to your init.el:
+
+#+BEGIN_SRC elisp
+  ;;; Initialize MELPA
+  (require 'package)
+  (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
+  (unless package-archive-contents (package-refresh-contents))
+  (package-initialize)
+
+  ;;; Install fsharp-mode
+  (unless (package-installed-p 'fsharp-mode)
+    (package-install 'fsharp-mode))
+
+  (require 'fsharp-mode)
+#+END_SRC
+
+If you are a user of [use-package](https://github.com/jwiegley/use-package) you can instead do
+
+#+BEGIN_SRC elisp
+(use-package fsharp-mode
+  :defer t
+  :ensure t)
+#+END_SRC
+
+*** From source
+
+I recommend to use [[https://cask.github.io/why-cask.html][Cask]]. Add this to your =Cask= file:
+
+#+BEGIN_SRC elisp
+(depends-on "fsharp-mode" :git "https://github.com/fsharp/emacs-fsharp-mode.git")
+#+END_SRC
+
+** Eglot integration
+
+=fsharp-eglot= is part of this package and provides integration to [[https://github.com/joaotavora/eglot][Eglot]] Emacs LSP client:
+
+   - Automatic =fsautocomplete= download
+   - Workaround for non-LSP standard-compliant
+
+Add to your config:
+#+BEGIN_SRC elisp
+(require 'fsharp-eglot)
+#+END_SRC
+
+and execute =M-x eglot=
+
+
+** Projects
+
+=fsharp-mode= has support for Emacs build-in project management via =project.el=
+
+** Configuration
+
+*** Compiler and REPL paths
+
+The F# compiler and interpreter should be set to good defaults for
+your OS as long as the relevant executables can be found on your PATH
+or in other standard locations. If you have a non-standard setup you
+may need to configure these paths manually.
+
+On Windows:
+
+#+BEGIN_SRC elisp
+(setq inferior-fsharp-program "c:\\Path\\To\\Fsi.exe")
+#+END_SRC
+
+On Unix-like systems, you must use the *--readline-* flag to ensure F#
+Interactive will work correctly with Emacs. Typically =fsi= and =fsc= are
+invoked through the shell scripts =fsharpi= and =fsharpc=:
+
+#+BEGIN_SRC elisp
+(setq inferior-fsharp-program "path/to/fsharpi --readline-")
+#+END_SRC
+
+***  Key Bindings
+
+If you are new to Emacs, you might want to use the menu (call
+=menu-bar-mode= if you don't see it). However, it's usually faster to learn
+a few useful bindings:
+
+| Key binding      | Description                               |
+|------------------+-------------------------------------------|
+| =C-c C-r=        | Evaluate region                           |
+| =C-c C-f=        | Load current buffer into toplevel         |
+| =C-c C-e=        | Evaluate current toplevel phrase          |
+| =C-M-x=          | Evaluate current toplevel phrase          |
+| =C-M-h=          | Mark current toplevel phrase              |
+| =C-c C-s=        | Show interactive buffer                   |
+| =C-c C-c=        | Compile with fsc                          |
+| =C-c x=          | Run the executable                        |
+| =C-c C-a=        | Open alternate file (.fsi or .fs)         |
+| =C-c l=          | Shift region to left                      |
+| =C-c r=          | Shift region to right                     |
+| =C-c <up>=       | Move cursor to the beginning of the block |
+| =C-c C-d=, =M-.= | Jump to definition of symbol at point     |
+| =C-c C-b=, =M-,= | Return to where point was before jump.    |
+
+
+To interrupt the interactive mode, use =C-c C-c=. This is useful if your
+code does an infinite loop or a very long computation.
+
+If you want to shift the region by 2 spaces, use: =M-2 C-c r=
+
+In the interactive buffer, use ==M-RET= to send the code without
+explicitly adding the =;;= thing.
+
+
+** Editor
+
+In order to change tab size it is possible to put this in emacs profile:
+
+#+BEGIN_SRC elisp
+(setq-default fsharp-indent-offset 2)
+#+END_SRC
+
+Because the F# language is sensitive to indentation, you might wan't to highlight indentation:
+
+#+BEGIN_SRC elisp
+(add-hook 'fsharp-mode-hook 'highlight-indentation-mode)
+#+END_SRC
+
+** Troubleshooting
+
+=fsharp-mode= is still under development, so you may encounter some
+issues. Please report them so we can improve things! Open an issue on [[https://github.com/fsharp/emacs-fsharp-mode/][Github]].
+
+*** Project file issues
+
+If your project file does not seem to be being parsed correctly, so
+that you have missing references or other incorrect intellisense
+results, it is possible to obtain a detailed log of LSP events in this buffers:
+
+
+- =*EGLOT (PROJECT/fsharp-mode) stderr*=
+- =*EGLOT (PROJECT/fsharp-mode) output*=
+- =*EGLOT (PROJECT/fsharp-mode) events*=
+
+** Contributing
+
+This project is maintained by the
+[[http://fsharp.org/][F# Software Foundation]], with the repository hosted
+on [[https://github.com/fsharp/emacs-fsharp-mode][GitHub]].
+
+Pull requests are welcome. Please run the test-suite with =make
+test= before submitting a pull request.
+
+*** Maintainers
+
+The maintainers of this repository appointed by the F# Core Engineering Group are:
+
+ - [[https://github.com/juergenhoetzel][Jürgen Hötzel]], [[http://github.com/forki][Steffen Forkmann]], [[http://github.com/kjnilsson][Karl Nilsson]] and [[http://github.com/guillermooo][Guillermo López-Anglada]]
+ - The primary maintainer for this repository is [[https://github.com/juergenhoetzel][Jürgen Hötzel]]
+
+Previous maintainers:
+ - [[https://github.com/rneatherway][Robin Neatherway]]
+
+
+
+

From 2dffc41792c2090fdfd427fc608a784d0aaab565 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Sun, 1 Dec 2019 17:15:17 +0100
Subject: [PATCH 022/147] Bump version number to 1.10

---
 CHANGELOG.md | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea2b998..2e89cac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,17 @@
+## 1.10 (2019.12-01)
+
+Features:
+  - #210: Remove old FsAutoComplete support (use LSP)
+	- provide eglot (Emacs LSP client) integration and add eglot
+      integration tests (using Emacs buttercup)
+    - Use Cask instead to automate the package development cycle;
+      development, dependencies, testing, building, packaging
+    - Make project.el aware of F# projects
+  - Use Emacs org-mode for README
+Bugfixes:
+    - #68: Indentation Cleanup / SMIE mode not being applied properly
+      (Gastove)
+
 ## 1.9.14 (2019-06-09)
 
 Features:

From a4f95b50cc894222471994298b81133acdbd6ab8 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Thu, 12 Dec 2019 20:55:36 +0100
Subject: [PATCH 023/147] Convert Markdown to Org mode links

---
 README.org | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/README.org b/README.org
index b34b066..41a2b0f 100644
--- a/README.org
+++ b/README.org
@@ -15,8 +15,8 @@ Provides support for the F# language in Emacs. Includes the following features:
 ** LSP mode
 Previous versions of =fsharp-mode= (mis)used a second repository [[https://github.com/rneatherway/emacs-fsharp-mode-bin][emacs-fsharp-mode-bin]] to distribute =fsautocomplete.exe= and =fsharp-mode= together.
 
-The current version of =fsharp-mode= installs =fsautocomplete.exe= automatically via  [eglot-fsharp](https://github.com/joaotavora/eglot) (part of this repo) or 
-[lsp-mode](https://github.com/emacs-lsp/lsp-mode) (untested).
+The current version of =fsharp-mode= installs =fsautocomplete.exe= automatically via [[https://github.com/joaotavora/eglot][eglot-fsharp]] (part of this repo) or
+[[https://github.com/emacs-lsp/lsp-mode][lsp-mode]] (untested).
 
 =fsharp-mode= is tested with Emacs 26.1+ and NET Core 2.1 (LTS)
 
@@ -26,7 +26,7 @@ The current version of =fsharp-mode= installs =fsautocomplete.exe= automatically
 
 *Currently the MELPA package is outdated*! ATM it still refers to  [[https://github.com/rneatherway/emacs-fsharp-mode-bin][emacs-fsharp-mode-bin]]!
 
-=fsharp-mode= is available on [MELPA](https://melpa.org) and can
+=fsharp-mode= is available on [[https://melpa.org][MELPA]] and can
 be installed using the built-in package manager.
 
 If you're not already using MELPA, add the following to your init.el:
@@ -45,7 +45,7 @@ If you're not already using MELPA, add the following to your init.el:
   (require 'fsharp-mode)
 #+END_SRC
 
-If you are a user of [use-package](https://github.com/jwiegley/use-package) you can instead do
+If you are a user of [[https://github.com/jwiegley/use-package][use-package]] you can instead do
 
 #+BEGIN_SRC elisp
 (use-package fsharp-mode

From bf88a5feb149c0dafcc7f7e32e46f776d842b935 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Thu, 12 Dec 2019 20:59:15 +0100
Subject: [PATCH 024/147] Melpa package is up2date

---
 README.org | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/README.org b/README.org
index 41a2b0f..919aafa 100644
--- a/README.org
+++ b/README.org
@@ -22,9 +22,7 @@ The current version of =fsharp-mode= installs =fsautocomplete.exe= automatically
 
 ** Installation
 
-*** Package (*OUTDATED*)
-
-*Currently the MELPA package is outdated*! ATM it still refers to  [[https://github.com/rneatherway/emacs-fsharp-mode-bin][emacs-fsharp-mode-bin]]!
+*** Package
 
 =fsharp-mode= is available on [[https://melpa.org][MELPA]] and can
 be installed using the built-in package manager.

From 6aff89a318329b1cbfcb4632dde4b0b02cadb6f0 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Thu, 12 Dec 2019 21:01:59 +0100
Subject: [PATCH 025/147] Adde MELPA stable badge

---
 README.org | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.org b/README.org
index 919aafa..3a5c795 100644
--- a/README.org
+++ b/README.org
@@ -1,4 +1,5 @@
 [[http://melpa.org/#/fsharp-mode][file:http://melpa.org/packages/fsharp-mode-badge.svg]]
+[[https://stable.melpa.org/#/fsharp-mode][file:https://stable.melpa.org/packages/fsharp-mode-badge.svg]]
 [[https://travis-ci.org/fsharp/emacs-fsharp-mode][file:https://travis-ci.org/fsharp/emacs-fsharp-mode.png]]
 * fsharp-mode
 

From fae57f3aa804213b1f69452b951951e9d5b68466 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Fri, 13 Dec 2019 17:13:03 +0100
Subject: [PATCH 026/147] Add .fsx completion issue workaround to README.org.
 Refs #231

---
 README.org | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/README.org b/README.org
index 3a5c795..2430b1b 100644
--- a/README.org
+++ b/README.org
@@ -154,6 +154,17 @@ Because the F# language is sensitive to indentation, you might wan't to highligh
 =fsharp-mode= is still under development, so you may encounter some
 issues. Please report them so we can improve things! Open an issue on [[https://github.com/fsharp/emacs-fsharp-mode/][Github]].
 
+*** No autocompletion in FSX files
+
+The root cause is documented in this Ionide issue:  [[https://github.com/ionide/ionide-vscode-fsharp/issues/1244][4.2.0 - No auto complete or typechecking in FSX files]]
+
+As a workaround can add a reference to the facade netstandard assembly (path is platform/SDK-dependent).
+
+On Arch Linux using [[https://aur.archlinux.org/packages/dotnet-sdk-lts-bin][dotnet sdk lts]] add this to your =fsx= file:
+#+BEGIN_SRC fsharp
+#r "/opt/dotnet/sdk/2.1.801/ref/netstandard.dll"
+#+END_SRC
+
 *** Project file issues
 
 If your project file does not seem to be being parsed correctly, so

From 352762d25a5ff55575e913b533096fa14d66d19c Mon Sep 17 00:00:00 2001
From: Dave Churchill <dave@ninthcuriosity.com>
Date: Tue, 14 Jan 2020 14:34:13 +1100
Subject: [PATCH 027/147] Correct the name of the eglot package

---
 README.org | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.org b/README.org
index 2430b1b..e6456e0 100644
--- a/README.org
+++ b/README.org
@@ -62,14 +62,14 @@ I recommend to use [[https://cask.github.io/why-cask.html][Cask]]. Add this to y
 
 ** Eglot integration
 
-=fsharp-eglot= is part of this package and provides integration to [[https://github.com/joaotavora/eglot][Eglot]] Emacs LSP client:
+=eglot-fsharp= is part of this package and provides integration to [[https://github.com/joaotavora/eglot][Eglot]] Emacs LSP client:
 
    - Automatic =fsautocomplete= download
    - Workaround for non-LSP standard-compliant
 
 Add to your config:
 #+BEGIN_SRC elisp
-(require 'fsharp-eglot)
+(require 'eglot-fsharp)
 #+END_SRC
 
 and execute =M-x eglot=

From d4d8a9435b1db6c02ff035016c6dbe6f9fee51b2 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Wed, 20 May 2020 20:31:50 +0200
Subject: [PATCH 028/147] Ensure a valid (windows) filename ist used for the
 temporary zip

Remove zip after unzip. Fixes #236
---
 eglot-fsharp.el | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index ca6b86c..bc5ff5a 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -71,7 +71,7 @@
 			  ".netcore."
 			".")))
 	 (exe (eglot-fsharp--path-to-server))
-	 (zip (concat (file-name-directory exe) (file-name-nondirectory url)))
+	 (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
 	 (gnutls-algorithm-priority
 	  (if (and (not gnutls-algorithm-priority)
 			  (boundp 'libgnutls-version)
@@ -84,7 +84,8 @@
       ;; FIXME: Windows
       (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
 	(unless (zerop (call-process "unzip" nil nil nil "-x" zip))
-	  (error "Failed to unzip %s" zip))))))
+	  (error "Failed to unzip %s" zip))
+	(delete-file zip)))))
 
  ;;;###autoload
 (defun eglot-fsharp (interactive)

From 35dccc57f9e47ee9b5f3ac0a48da975709759bbe Mon Sep 17 00:00:00 2001
From: Florian Biermann <florian.biermann@simcorp.com>
Date: Fri, 28 Aug 2020 13:45:27 +0200
Subject: [PATCH 029/147] Execute binary directly on Windows

---
 eglot-fsharp.el | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index bc5ff5a..411752f 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -95,10 +95,10 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
     (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (cons 'eglot-fsautocomplete
-	  `(,(if (eq eglot-fsharp-server-runtime 'net-core)
-		 "dotnet"
-	       ;; FIXME: Windows
-	       "mono") ,(eglot-fsharp--path-to-server) "--background-service-enabled"))))
+	  `(,(cond ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
+               ((eq window-system 'w32) "")
+               ("mono"))
+        ,(eglot-fsharp--path-to-server) "--background-service-enabled"))))
 
 
 (defclass eglot-fsautocomplete (eglot-lsp-server) ()

From 8c60c55ca90769ab0a570db62c1616dce598bc80 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 30 Aug 2020 18:02:56 +0200
Subject: [PATCH 030/147] Conform to Emacs Lisp style guide

https://github.com/bbatsov/emacs-lisp-style-guide
---
 eglot-fsharp.el | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 411752f..025324d 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -95,9 +95,10 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
     (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (cons 'eglot-fsautocomplete
-	  `(,(cond ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
-               ((eq window-system 'w32) "")
-               ("mono"))
+	  `(,(cond
+	      ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
+              ((eq window-system 'w32) "")
+              (t "mono"))
         ,(eglot-fsharp--path-to-server) "--background-service-enabled"))))
 
 

From 1605ac0adfaebabbcc77f965e466e2649075d626 Mon Sep 17 00:00:00 2001
From: wasuken <wevorence@gmail.com>
Date: Sun, 27 Sep 2020 10:25:18 +0900
Subject: [PATCH 031/147] Installing of FsAutoComplete from github instead of
 appveyor.

Fixes issue #245.
---
 eglot-fsharp.el | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 025324d..1e96995 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -66,10 +66,11 @@
 (defun eglot-fsharp--maybe-install ()
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
   (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
-  (let* ((url (format "https://ci.appveyor.com/api/projects/fsautocomplete/fsautocomplete/artifacts/bin/pkgs/fsautocomplete%szip?branch=master"
-		      (if (eq eglot-fsharp-server-runtime 'net-core)
-			  ".netcore."
-			".")))
+  (let* ((url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
+					  eglot-fsharp-server-version
+					  (if (eq eglot-fsharp-server-runtime 'net-core)
+						  ".netcore."
+						".")))
 	 (exe (eglot-fsharp--path-to-server))
 	 (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
 	 (gnutls-algorithm-priority

From 4f8db41446aa960368e791bc747ce822b8b1f126 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 2 Oct 2020 08:24:54 +0200
Subject: [PATCH 032/147] Update to latest fsautocomplete.exe release

---
 eglot-fsharp.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 1e96995..6066bc8 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -41,7 +41,7 @@
   :risky t
   :type 'directory)
 
-(defcustom eglot-fsharp-server-version "0.38.1"
+(defcustom eglot-fsharp-server-version "0.41.1"
   "FsAutoComplete version."
   :group 'eglot-fsharp
   :risky t

From 6ca9156e5c71db56893924c5331a6e04b02e27b8 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Thu, 1 Oct 2020 07:54:50 +0200
Subject: [PATCH 033/147] Use Github Actions instead of .travis CI

---
 .github/workflows/test.yml | 31 ++++++++++++++++++++++++++++
 .travis.yml                | 42 --------------------------------------
 README.org                 |  2 +-
 3 files changed, 32 insertions(+), 43 deletions(-)
 create mode 100644 .github/workflows/test.yml
 delete mode 100644 .travis.yml

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..9f50064
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,31 @@
+name: "CI"
+on:
+  pull_request:
+  push:
+    # Comment out this section to enable testing of all branches.
+    branches:
+      - master
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        emacs_version:
+          - 26.3
+          - 27.1
+          - snapshot
+    steps:
+    - uses: purcell/setup-emacs@master
+      with:
+        version: ${{ matrix.emacs_version }}
+    - uses: actions/setup-dotnet@v1
+    - uses: actions/checkout@v2
+    - uses: conao3/setup-cask@master
+    - name: Show dotnet sdks
+      run: dotnet --list-sdks
+    - name: Show dotnet version
+      run: dotnet --info
+    - name: Test
+      run: make test
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 67c757a..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-language: emacs-lisp
-# Emacs fails to build in container-based builds on Travis
-# See https://github.com/travis-ci/travis-ci/issues/9061
-# and https://github.com/moby/moby/issues/22801
-sudo: required
-dist: bionic
-cache:
-  - directories:
-      # Cache stable Emacs binaries (saves 1min per job)
-      - "$HOME/emacs/"
-# Allow Emacs snapshot builds to fail and don’t wait for these as they can take
-# a looooong time
-matrix:
-  fast_finish: true
-  allow_failures:
-    - env: EMACS_VERSION=emacs-snapshot
-env:
-  - EMACS_VERSION=emacs26
-  - EMACS_VERSION=emacs-snapshot
-
-before_install:
-    # Emacs kelleyk PPA
-  - sudo add-apt-repository -y ppa:kelleyk/emacs
-  - sudo apt-get update
-  - sudo apt install $EMACS_VERSION-nox
-  - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-  - wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
-  - sudo dpkg -i packages-microsoft-prod.deb
-  - sudo apt-get update
-  - sudo apt-get install apt-transport-https
-  - sudo apt-get update
-  - sudo apt-get install dotnet-sdk-2.1
-  - export PATH="$HOME/bin:$PATH"
-  - export EMACS=$EMACS_VERSION
-  # Download the makefile to emacs-travis.mk
-  - wget 'https://raw.githubusercontent.com/flycheck/emacs-travis/master/emacs-travis.mk'
-  # Install Emacs (according to $EMACS_VERSION) and Cask
-  - make -f emacs-travis.mk install_cask
-  - travis_retry sudo apt-get install -y fsharp
-
-script:
-  - make test
diff --git a/README.org b/README.org
index e6456e0..13fa47a 100644
--- a/README.org
+++ b/README.org
@@ -1,6 +1,6 @@
 [[http://melpa.org/#/fsharp-mode][file:http://melpa.org/packages/fsharp-mode-badge.svg]]
 [[https://stable.melpa.org/#/fsharp-mode][file:https://stable.melpa.org/packages/fsharp-mode-badge.svg]]
-[[https://travis-ci.org/fsharp/emacs-fsharp-mode][file:https://travis-ci.org/fsharp/emacs-fsharp-mode.png]]
+[[https://github.com/fsharp/emacs-fsharp-mode/actions][file:https://github.com/fsharp/emacs-fsharp-mode/workflows/CI/badge.svg]]
 * fsharp-mode
 
 Provides support for the F# language in Emacs. Includes the following features:

From 89ea972c92e2e57c9f3335e037dee863834fef9b Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sat, 3 Oct 2020 14:22:08 +0200
Subject: [PATCH 034/147] Add Github Action for windows-latest

This implementation is a hack:
- Cask still doesn't work on windows: https://github.com/cask/cask/pull/449. We use a checkout of this pull-request.
- Make doesn't work on windows: We use multiple "cask.bat" invocations to do the test.

The best long term solution seems to switch to eldev.
---
 .github/workflows/test.yml | 31 +++++++++++++++++++++++++++++--
 Cask                       |  2 +-
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9f50064..4b9675f 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -5,9 +5,8 @@ on:
     # Comment out this section to enable testing of all branches.
     branches:
       - master
-
 jobs:
-  build:
+  gnu-build:
     runs-on: ubuntu-latest
     strategy:
       fail-fast: false
@@ -29,3 +28,31 @@ jobs:
       run: dotnet --info
     - name: Test
       run: make test
+  windows-build:
+    runs-on: windows-latest
+    strategy:
+      fail-fast: false
+    steps:
+    - uses: actions/setup-dotnet@v1
+    - name: Install Cask/scoop-emacs
+      run: |
+        Set-ExecutionPolicy RemoteSigned -scope CurrentUser
+        Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
+        scoop update
+        scoop bucket add extras
+        scoop install emacs
+        scoop install make
+        echo "$env:PATH" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
+    - uses: actions/checkout@v2
+    - name: Test                # FIXME: cask hack
+      run: |
+        git clone https://github.com/tom-bowles/cask cask-windows
+        Remove-Item -recurse .\cask-windows\test
+        dotnet restore test/Test1
+        Invoke-WebRequest -Uri https://raw.githubusercontent.com/joaotavora/eglot/master/eglot-tests.el -OutFile eglot-tests.el
+        Start .\Cask-windows\bin\cask.bat -ArgumentList install -NoNewWindow -Wait
+        Start .\Cask-windows\bin\cask.bat -ArgumentList build -NoNewWindow -Wait
+        Start .\Cask-windows\bin\cask.bat -ArgumentList "exec buttercup -L . -L test --traceback full" -NoNewWindow -Wait
+
+
+
diff --git a/Cask b/Cask
index 2a9191a..dc1eaf7 100644
--- a/Cask
+++ b/Cask
@@ -4,6 +4,6 @@
 (package-file "fsharp-mode.el")
 (files "*.el")
 ;; FIXME: Use multiple packages: https://github.com/melpa/melpa#example-multiple-packages-in-one-repository ?
-
 (development
  (depends-on "buttercup"))
+

From d4ea76ed761c1d15b5fdc32418f0050a59f20702 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 4 Oct 2020 13:34:36 +0200
Subject: [PATCH 035/147] Remove Appveyor CI Job (obsoleted by GH Actions)

---
 .appveyor/test.bat |  5 -----
 appveyor.yml       | 20 --------------------
 2 files changed, 25 deletions(-)
 delete mode 100755 .appveyor/test.bat
 delete mode 100644 appveyor.yml

diff --git a/.appveyor/test.bat b/.appveyor/test.bat
deleted file mode 100755
index 80d6048..0000000
--- a/.appveyor/test.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-set HOME=%~dp0\tmp
-
-emacs -l test\test-common.el --batch --eval "(progn (set-default-coding-systems 'utf-8) (load-packages))"
-
-emacs -l test\test-common.el --batch --eval "(progn (set-default-coding-systems 'utf-8) (run-fsharp-unit-tests))"
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 67f25e2..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-environment:
-  FSACVERSION: 0.34.0
-  FSharpBinding_BlockingTimeout: 1000
-  FSharpBinding_MaxTimeout: 10000
-matrix:
-  fast_finish: true
-install:
-  - ps: Start-FileDownload "https://github.com/fsharp/FSharp.AutoComplete/releases/download/$env:FSACVERSION/fsautocomplete.zip"
-  - ps: 7z x fsautocomplete.zip -oemacs-fsharp-mode\bin | select-string -notmatch "ing  "
-  - ps: iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
-  - ps: scoop install coreutils
-  - ps: scoop install make
-  - ps: scoop install grep
-  - ps: scoop install unzip
-  - ps: scoop bucket add extras
-  - ps: scoop install emacs
-build_script:
-  - cmd: .\.appveyor\test.bat
-test: off
- 

From 9f2ed8e6ff6855ef109b9ea1308a7c8e2709c624 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Thu, 8 Oct 2020 20:28:42 +0200
Subject: [PATCH 036/147] Add the possibility to always install the latest
 version

Setting `eglot-fsharp-server-version' to 'latest will always install
the latest fsautocomplete version.

At every start of `eglot-fsharp' it is checked if the installed
version is outdated.

The github version check is done only once per session, so performance
is not affected too much.
---
 eglot-fsharp.el | 66 ++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 51 insertions(+), 15 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 6066bc8..8904db1 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -1,6 +1,6 @@
 ;;; eglot-fsharp.el --- Lua eglot integration                     -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019  Jürgen Hötzel
+;; Copyright (C) 2019-2020  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@archlinux.org>
 ;; Package-Requires: ((eglot "1.4"))
@@ -41,11 +41,13 @@
   :risky t
   :type 'directory)
 
-(defcustom eglot-fsharp-server-version "0.41.1"
-  "FsAutoComplete version."
+(defcustom eglot-fsharp-server-version 'latest
+  "FsAutoComplete version to install or update."
   :group 'eglot-fsharp
   :risky t
-  :type 'string)
+  :type '(choice
+	  (const :tag "Latest release" latest)
+	  (string :tag "Version string")))
 
 (defcustom eglot-fsharp-server-runtime
   (if (executable-find "dotnet")
@@ -63,14 +65,48 @@
 			     "netcore/fsautocomplete.dll"
 			   "netframework/fsautocomplete.exe"))))
 
+;; cache to prevent repetitive queries
+(defvar eglot-fsharp--github-version nil "Latest fsautocomplete.exe GitHub version string.")
+
+(defun eglot-fsharp--github-version ()
+  "Return latest fsautocomplete.exe GitHub version string."
+  (or eglot-fsharp--github-version
+      (with-temp-buffer
+	(condition-case err
+	    (let ((json-object-type 'hash-table)
+		  (url-mime-accept-string "application/json"))
+	      (url-insert-file-contents "https://github.com/fsharp/fsautocomplete/releases/latest")
+	      (setq eglot-fsharp--github-version (gethash "tag_name" (json-parse-buffer))))
+	  (file-error
+	   (warn "fsautocomplete.exe update check:: %s" (error-message-string err)))))))
+
+(defun eglot-fsharp--installed-version ()
+  "Return version string of fsautocomplete."
+  (when (file-exists-p (eglot-fsharp--path-to-server))
+    (let* ((cmd (append (cdr (eglot-fsharp nil)) '("--version")))
+	   (version-line (concat (car (apply #'process-lines cmd )))))
+      (when (string-match "^FsAutoComplete \\([[:digit:].]+\\) " version-line)
+	(substring version-line (match-beginning 1) (match-end 1))
+	(match-string 1 version-line)))))
+
+(defun eglot-fsharp-current-version-p ()
+  "Return t if the installation is not outdated."
+  (when (file-exists-p (eglot-fsharp--path-to-server))
+    (if (eq eglot-fsharp-server-version 'latest)
+	(equal (eglot-fsharp--github-version) (eglot-fsharp--installed-version))
+      (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
+
 (defun eglot-fsharp--maybe-install ()
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
   (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
-  (let* ((url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
-					  eglot-fsharp-server-version
-					  (if (eq eglot-fsharp-server-runtime 'net-core)
-						  ".netcore."
-						".")))
+  (let* ((version (if (eq eglot-fsharp-server-version 'latest)
+		      (eglot-fsharp--github-version)
+		    eglot-fsharp-server-version))
+	 (url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
+		      version
+		      (if (eq eglot-fsharp-server-runtime 'net-core)
+			  ".netcore."
+			".")))
 	 (exe (eglot-fsharp--path-to-server))
 	 (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
 	 (gnutls-algorithm-priority
@@ -79,20 +115,20 @@
 			  (>= libgnutls-version 30603)
 			  (version<= emacs-version "26.2"))
 		     "NORMAL:-VERS-TLS1.3"
-		   gnutls-algorithm-priority)))
-    (unless (file-exists-p exe)
+	    gnutls-algorithm-priority)))
+    (unless (eglot-fsharp-current-version-p)
       (url-copy-file url zip t)
-      ;; FIXME: Windows
+      ;; FIXME: Windows (unzip preinstalled?)
       (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
-	(unless (zerop (call-process "unzip" nil nil nil "-x" zip))
+	(unless (zerop (call-process "unzip" nil nil nil "-o" zip))
 	  (error "Failed to unzip %s" zip))
 	(delete-file zip)))))
 
  ;;;###autoload
 (defun eglot-fsharp (interactive)
-"Return `eglot' contact when FsAutoComplete is installed.
+  "Return `eglot' contact when FsAutoComplete is installed.
 Ensure FsAutoComplete is installed (when called INTERACTIVE)."
-  (unless (or (file-exists-p (eglot-fsharp--path-to-server)) (not interactive))
+  (when interactive
     (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (cons 'eglot-fsautocomplete

From 2883aefce6735dbf52c522faf9e2a9a9a4192671 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Mon, 12 Oct 2020 18:30:00 +0200
Subject: [PATCH 037/147] Use json-read instead of json-parse-buffer

This restores compatibility to Emacs 26.3. The native JSON functions
are only available since Emacs 27.1.
---
 eglot-fsharp.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 8904db1..24b7bb4 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -76,7 +76,8 @@
 	    (let ((json-object-type 'hash-table)
 		  (url-mime-accept-string "application/json"))
 	      (url-insert-file-contents "https://github.com/fsharp/fsautocomplete/releases/latest")
-	      (setq eglot-fsharp--github-version (gethash "tag_name" (json-parse-buffer))))
+	      (goto-char (point-min))
+	      (setq eglot-fsharp--github-version (gethash "tag_name" (json-read))))
 	  (file-error
 	   (warn "fsautocomplete.exe update check:: %s" (error-message-string err)))))))
 

From 0071a66f0919b8c0da0089073357ad42271d90e5 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 8 Dec 2020 11:30:00 +0100
Subject: [PATCH 038/147] Remove unused local variables

Fixes #255 (interference with company-mode)
---
 fsharp-mode.el | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index e2f00b4..6b99fee 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -199,12 +199,7 @@
           add-log-current-defun-function
           underline-minimum-offset
           compile-command
-          syntax-propertize-function
-          company-backends
-          company-auto-complete
-          company-auto-complete-chars
-          company-require-match
-          company-tooltip-align-annotations))
+          syntax-propertize-function))
 
   (setq local-abbrev-table       fsharp-mode-abbrev-table
         paragraph-start          (concat "^$\\|" page-delimiter)

From c4e9243cb0fe07f7d82884ef24f2a4684a632d05 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sat, 2 Jan 2021 11:30:00 +0100
Subject: [PATCH 039/147] Prepare eglot-fsharp package split

Refs #253
---
 eglot-fsharp.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 24b7bb4..e8d8b66 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -1,9 +1,9 @@
 ;;; eglot-fsharp.el --- Lua eglot integration                     -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019-2020  Jürgen Hötzel
+;; Copyright (C) 2019-2021  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@archlinux.org>
-;; Package-Requires: ((eglot "1.4"))
+;; Package-Requires: ((eglot "1.4") (fsharp-mode "1.10"))
 ;; Keywords: languages
 
 ;; This program is free software; you can redistribute it and/or modify

From 93b3e0036121eec298fe26f1267dd61944612b7a Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Wed, 6 Jan 2021 06:51:01 +0100
Subject: [PATCH 040/147] Replace dash.el with seq.el

Emacs 25 ships with a sequence library named seq.el. This renders
dash.el completely obsolete.
---
 fsharp-mode-font.el | 3 ---
 fsharp-mode-util.el | 1 -
 fsharp-mode.el      | 7 +++----
 3 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/fsharp-mode-font.el b/fsharp-mode-font.el
index 8f0b3e2..a063919 100644
--- a/fsharp-mode-font.el
+++ b/fsharp-mode-font.el
@@ -28,9 +28,6 @@
 
 ;;; Code:
 
-;; (require 'fsharp-mode)
-;; (require 'dash)
-
 (defgroup fsharp-ui nil
   "F# UI group for the defcustom interface."
   :prefix "fsharp-ui-"
diff --git a/fsharp-mode-util.el b/fsharp-mode-util.el
index 416ddd3..daa65fb 100644
--- a/fsharp-mode-util.el
+++ b/fsharp-mode-util.el
@@ -24,7 +24,6 @@
 ;; Boston, MA 02110-1301, USA.
 
 (with-no-warnings (require 'cl))
-(require 'dash)
 
 (defvar fsharp-ac-using-mono
   (case system-type
diff --git a/fsharp-mode.el b/fsharp-mode.el
index 6b99fee..4b28966 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -7,7 +7,7 @@
 ;;         2012-2014 Robin Neatherway <robin.neatherway@gmail.com>
 ;;         2017-2019 Jürgen Hötzel
 ;; Maintainer: Jürgen Hötzel
-;; Package-Requires: ((emacs "25")  (s "1.3.1") (dash "1.1.0") (eglot))
+;; Package-Requires: ((emacs "25")  (s "1.3.1") (eglot))
 ;; Keywords: languages
 ;; Version: 1.9.15
 
@@ -35,7 +35,6 @@
 (require 'fsharp-mode-util)
 (require 'compile)
 (require 'project)
-(require 'dash)
 
 (defgroup fsharp nil
   "Support for the Fsharp programming language, <http://www.fsharp.net/>"
@@ -45,11 +44,11 @@
 ;;; Compilation
 
 (defvar fsharp-compile-command
-  (-any #'fsharp-mode--executable-find '("fsharpc" "fsc"))
+  (seq-some #'fsharp-mode--executable-find '("fsharpc" "fsc"))
   "The program used to compile F# source files.")
 
 (defvar fsharp-build-command
-  (-any #'fsharp-mode--msbuild-find '("msbuild" "xbuild"))
+  (seq-some #'fsharp-mode--msbuild-find '("msbuild" "xbuild"))
   "The command used to build F# projects and solutions.")
 
 ;;; ----------------------------------------------------------------------------

From 08025f3892ea94c77dcbd644a75be23f3d9a3b23 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Mon, 11 Jan 2021 16:04:52 +0100
Subject: [PATCH 041/147] Fix compiler warning: Remove unused expression

---
 eglot-fsharp.el | 1 -
 1 file changed, 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index e8d8b66..d383816 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -87,7 +87,6 @@
     (let* ((cmd (append (cdr (eglot-fsharp nil)) '("--version")))
 	   (version-line (concat (car (apply #'process-lines cmd )))))
       (when (string-match "^FsAutoComplete \\([[:digit:].]+\\) " version-line)
-	(substring version-line (match-beginning 1) (match-end 1))
 	(match-string 1 version-line)))))
 
 (defun eglot-fsharp-current-version-p ()

From ede394b0a755b55c6135578b0434ba05f8ab5022 Mon Sep 17 00:00:00 2001
From: JenChieh <jcs090218@gmail.com>
Date: Fri, 15 Jan 2021 14:50:46 +0800
Subject: [PATCH 042/147] Fixed mix tabs and spaces

---
 eglot-fsharp.el | 84 ++++++++++++++++++++++++-------------------------
 1 file changed, 42 insertions(+), 42 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index e8d8b66..7aff207 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -46,8 +46,8 @@
   :group 'eglot-fsharp
   :risky t
   :type '(choice
-	  (const :tag "Latest release" latest)
-	  (string :tag "Version string")))
+      (const :tag "Latest release" latest)
+      (string :tag "Version string")))
 
 (defcustom eglot-fsharp-server-runtime
   (if (executable-find "dotnet")
@@ -61,9 +61,9 @@
 (defun eglot-fsharp--path-to-server ()
   "Return FsAutoComplete path."
   (file-truename (concat eglot-fsharp-server-install-dir
-			 (if (eq eglot-fsharp-server-runtime 'net-core)
-			     "netcore/fsautocomplete.dll"
-			   "netframework/fsautocomplete.exe"))))
+             (if (eq eglot-fsharp-server-runtime 'net-core)
+                 "netcore/fsautocomplete.dll"
+               "netframework/fsautocomplete.exe"))))
 
 ;; cache to prevent repetitive queries
 (defvar eglot-fsharp--github-version nil "Latest fsautocomplete.exe GitHub version string.")
@@ -72,58 +72,58 @@
   "Return latest fsautocomplete.exe GitHub version string."
   (or eglot-fsharp--github-version
       (with-temp-buffer
-	(condition-case err
-	    (let ((json-object-type 'hash-table)
-		  (url-mime-accept-string "application/json"))
-	      (url-insert-file-contents "https://github.com/fsharp/fsautocomplete/releases/latest")
-	      (goto-char (point-min))
-	      (setq eglot-fsharp--github-version (gethash "tag_name" (json-read))))
-	  (file-error
-	   (warn "fsautocomplete.exe update check:: %s" (error-message-string err)))))))
+    (condition-case err
+        (let ((json-object-type 'hash-table)
+          (url-mime-accept-string "application/json"))
+          (url-insert-file-contents "https://github.com/fsharp/fsautocomplete/releases/latest")
+          (goto-char (point-min))
+          (setq eglot-fsharp--github-version (gethash "tag_name" (json-read))))
+      (file-error
+       (warn "fsautocomplete.exe update check:: %s" (error-message-string err)))))))
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (let* ((cmd (append (cdr (eglot-fsharp nil)) '("--version")))
-	   (version-line (concat (car (apply #'process-lines cmd )))))
+       (version-line (concat (car (apply #'process-lines cmd )))))
       (when (string-match "^FsAutoComplete \\([[:digit:].]+\\) " version-line)
-	(substring version-line (match-beginning 1) (match-end 1))
-	(match-string 1 version-line)))))
+    (substring version-line (match-beginning 1) (match-end 1))
+    (match-string 1 version-line)))))
 
 (defun eglot-fsharp-current-version-p ()
   "Return t if the installation is not outdated."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (if (eq eglot-fsharp-server-version 'latest)
-	(equal (eglot-fsharp--github-version) (eglot-fsharp--installed-version))
+    (equal (eglot-fsharp--github-version) (eglot-fsharp--installed-version))
       (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
 
 (defun eglot-fsharp--maybe-install ()
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
   (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
   (let* ((version (if (eq eglot-fsharp-server-version 'latest)
-		      (eglot-fsharp--github-version)
-		    eglot-fsharp-server-version))
-	 (url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
-		      version
-		      (if (eq eglot-fsharp-server-runtime 'net-core)
-			  ".netcore."
-			".")))
-	 (exe (eglot-fsharp--path-to-server))
-	 (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
-	 (gnutls-algorithm-priority
-	  (if (and (not gnutls-algorithm-priority)
-			  (boundp 'libgnutls-version)
-			  (>= libgnutls-version 30603)
-			  (version<= emacs-version "26.2"))
-		     "NORMAL:-VERS-TLS1.3"
-	    gnutls-algorithm-priority)))
+              (eglot-fsharp--github-version)
+            eglot-fsharp-server-version))
+     (url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
+              version
+              (if (eq eglot-fsharp-server-runtime 'net-core)
+              ".netcore."
+            ".")))
+     (exe (eglot-fsharp--path-to-server))
+     (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
+     (gnutls-algorithm-priority
+      (if (and (not gnutls-algorithm-priority)
+              (boundp 'libgnutls-version)
+              (>= libgnutls-version 30603)
+              (version<= emacs-version "26.2"))
+             "NORMAL:-VERS-TLS1.3"
+        gnutls-algorithm-priority)))
     (unless (eglot-fsharp-current-version-p)
       (url-copy-file url zip t)
       ;; FIXME: Windows (unzip preinstalled?)
       (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
-	(unless (zerop (call-process "unzip" nil nil nil "-o" zip))
-	  (error "Failed to unzip %s" zip))
-	(delete-file zip)))))
+    (unless (zerop (call-process "unzip" nil nil nil "-o" zip))
+      (error "Failed to unzip %s" zip))
+    (delete-file zip)))))
 
  ;;;###autoload
 (defun eglot-fsharp (interactive)
@@ -133,8 +133,8 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
     (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (cons 'eglot-fsautocomplete
-	  `(,(cond
-	      ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
+      `(,(cond
+          ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
               ((eq window-system 'w32) "")
               (t "mono"))
         ,(eglot-fsharp--path-to-server) "--background-service-enabled"))))
@@ -152,10 +152,10 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   "FsAutoComplete breaks spec and and returns error instead of empty list."
   (if (eq major-mode 'fsharp-mode)
       (condition-case err
-	  (cl-call-next-method)
-	(jsonrpc-error
-	 (when (equal (cadddr err) '(jsonrpc-error-message . "Could not find declaration"))
-	   nil)))
+      (cl-call-next-method)
+    (jsonrpc-error
+     (when (equal (cadddr err) '(jsonrpc-error-message . "Could not find declaration"))
+       nil)))
     (when (cl-next-method-p)
       (cl-call-next-method))))
 

From 45ea30cc4f2806504cf1e79a4a5d2cd04be50ff4 Mon Sep 17 00:00:00 2001
From: JenChieh <jcs090218@gmail.com>
Date: Fri, 15 Jan 2021 14:51:21 +0800
Subject: [PATCH 043/147] Fixed indentation

---
 eglot-fsharp.el | 86 ++++++++++++++++++++++++-------------------------
 1 file changed, 43 insertions(+), 43 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 7aff207..f0ef542 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -46,8 +46,8 @@
   :group 'eglot-fsharp
   :risky t
   :type '(choice
-      (const :tag "Latest release" latest)
-      (string :tag "Version string")))
+          (const :tag "Latest release" latest)
+          (string :tag "Version string")))
 
 (defcustom eglot-fsharp-server-runtime
   (if (executable-find "dotnet")
@@ -61,9 +61,9 @@
 (defun eglot-fsharp--path-to-server ()
   "Return FsAutoComplete path."
   (file-truename (concat eglot-fsharp-server-install-dir
-             (if (eq eglot-fsharp-server-runtime 'net-core)
-                 "netcore/fsautocomplete.dll"
-               "netframework/fsautocomplete.exe"))))
+                         (if (eq eglot-fsharp-server-runtime 'net-core)
+                             "netcore/fsautocomplete.dll"
+                           "netframework/fsautocomplete.exe"))))
 
 ;; cache to prevent repetitive queries
 (defvar eglot-fsharp--github-version nil "Latest fsautocomplete.exe GitHub version string.")
@@ -72,58 +72,58 @@
   "Return latest fsautocomplete.exe GitHub version string."
   (or eglot-fsharp--github-version
       (with-temp-buffer
-    (condition-case err
-        (let ((json-object-type 'hash-table)
-          (url-mime-accept-string "application/json"))
-          (url-insert-file-contents "https://github.com/fsharp/fsautocomplete/releases/latest")
-          (goto-char (point-min))
-          (setq eglot-fsharp--github-version (gethash "tag_name" (json-read))))
-      (file-error
-       (warn "fsautocomplete.exe update check:: %s" (error-message-string err)))))))
+        (condition-case err
+            (let ((json-object-type 'hash-table)
+                  (url-mime-accept-string "application/json"))
+              (url-insert-file-contents "https://github.com/fsharp/fsautocomplete/releases/latest")
+              (goto-char (point-min))
+              (setq eglot-fsharp--github-version (gethash "tag_name" (json-read))))
+          (file-error
+           (warn "fsautocomplete.exe update check:: %s" (error-message-string err)))))))
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (let* ((cmd (append (cdr (eglot-fsharp nil)) '("--version")))
-       (version-line (concat (car (apply #'process-lines cmd )))))
+           (version-line (concat (car (apply #'process-lines cmd )))))
       (when (string-match "^FsAutoComplete \\([[:digit:].]+\\) " version-line)
-    (substring version-line (match-beginning 1) (match-end 1))
-    (match-string 1 version-line)))))
+        (substring version-line (match-beginning 1) (match-end 1))
+        (match-string 1 version-line)))))
 
 (defun eglot-fsharp-current-version-p ()
   "Return t if the installation is not outdated."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (if (eq eglot-fsharp-server-version 'latest)
-    (equal (eglot-fsharp--github-version) (eglot-fsharp--installed-version))
+        (equal (eglot-fsharp--github-version) (eglot-fsharp--installed-version))
       (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
 
 (defun eglot-fsharp--maybe-install ()
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
   (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
   (let* ((version (if (eq eglot-fsharp-server-version 'latest)
-              (eglot-fsharp--github-version)
-            eglot-fsharp-server-version))
-     (url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
-              version
-              (if (eq eglot-fsharp-server-runtime 'net-core)
-              ".netcore."
-            ".")))
-     (exe (eglot-fsharp--path-to-server))
-     (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
-     (gnutls-algorithm-priority
-      (if (and (not gnutls-algorithm-priority)
-              (boundp 'libgnutls-version)
-              (>= libgnutls-version 30603)
-              (version<= emacs-version "26.2"))
-             "NORMAL:-VERS-TLS1.3"
-        gnutls-algorithm-priority)))
+                      (eglot-fsharp--github-version)
+                    eglot-fsharp-server-version))
+         (url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
+                      version
+                      (if (eq eglot-fsharp-server-runtime 'net-core)
+                          ".netcore."
+                        ".")))
+         (exe (eglot-fsharp--path-to-server))
+         (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
+         (gnutls-algorithm-priority
+          (if (and (not gnutls-algorithm-priority)
+                   (boundp 'libgnutls-version)
+                   (>= libgnutls-version 30603)
+                   (version<= emacs-version "26.2"))
+              "NORMAL:-VERS-TLS1.3"
+            gnutls-algorithm-priority)))
     (unless (eglot-fsharp-current-version-p)
       (url-copy-file url zip t)
       ;; FIXME: Windows (unzip preinstalled?)
       (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
-    (unless (zerop (call-process "unzip" nil nil nil "-o" zip))
-      (error "Failed to unzip %s" zip))
-    (delete-file zip)))))
+        (unless (zerop (call-process "unzip" nil nil nil "-o" zip))
+          (error "Failed to unzip %s" zip))
+        (delete-file zip)))))
 
  ;;;###autoload
 (defun eglot-fsharp (interactive)
@@ -133,11 +133,11 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
     (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (cons 'eglot-fsautocomplete
-      `(,(cond
-          ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
+          `(,(cond
+              ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
               ((eq window-system 'w32) "")
               (t "mono"))
-        ,(eglot-fsharp--path-to-server) "--background-service-enabled"))))
+            ,(eglot-fsharp--path-to-server) "--background-service-enabled"))))
 
 
 (defclass eglot-fsautocomplete (eglot-lsp-server) ()
@@ -152,10 +152,10 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   "FsAutoComplete breaks spec and and returns error instead of empty list."
   (if (eq major-mode 'fsharp-mode)
       (condition-case err
-      (cl-call-next-method)
-    (jsonrpc-error
-     (when (equal (cadddr err) '(jsonrpc-error-message . "Could not find declaration"))
-       nil)))
+          (cl-call-next-method)
+        (jsonrpc-error
+         (when (equal (cadddr err) '(jsonrpc-error-message . "Could not find declaration"))
+           nil)))
     (when (cl-next-method-p)
       (cl-call-next-method))))
 

From 310320e998c433d65ef6a303c36474c69293d6fa Mon Sep 17 00:00:00 2001
From: JenChieh <jcs090218@gmail.com>
Date: Fri, 15 Jan 2021 14:52:33 +0800
Subject: [PATCH 044/147] Correct footer

---
 eglot-fsharp.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index f0ef542..34c12f4 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -162,4 +162,4 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
 (add-to-list 'eglot-server-programs `(fsharp-mode . eglot-fsharp))
 
 (provide 'eglot-fsharp)
-;;; eglot-fsharp.el ends herep
+;;; eglot-fsharp.el ends here

From 4cb097cf72d8a127a66baa3baa0b3f91662debde Mon Sep 17 00:00:00 2001
From: JenChieh <jcs090218@gmail.com>
Date: Fri, 15 Jan 2021 15:00:49 +0800
Subject: [PATCH 045/147] Fixed byte compile warnings

---
 eglot-fsharp.el | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 34c12f4..11b4d87 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -85,9 +85,8 @@
   "Return version string of fsautocomplete."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (let* ((cmd (append (cdr (eglot-fsharp nil)) '("--version")))
-           (version-line (concat (car (apply #'process-lines cmd )))))
+           (version-line (concat (car (apply #'process-lines cmd)))))
       (when (string-match "^FsAutoComplete \\([[:digit:].]+\\) " version-line)
-        (substring version-line (match-beginning 1) (match-end 1))
         (match-string 1 version-line)))))
 
 (defun eglot-fsharp-current-version-p ()
@@ -143,19 +142,18 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
 (defclass eglot-fsautocomplete (eglot-lsp-server) ()
   :documentation "F# FsAutoComplete langserver.")
 
-(cl-defmethod eglot-initialization-options ((server eglot-fsautocomplete))
+(cl-defmethod eglot-initialization-options ((_server eglot-fsautocomplete))
   "Passes through required FsAutoComplete initialization options."
   '(:automaticWorkspaceInit t))
 
 ;; FIXME: this should be fixed in FsAutocomplete
-(cl-defmethod xref-backend-definitions :around ((type symbol) _identifier)
+(cl-defmethod xref-backend-definitions :around ((_type symbol) _identifier)
   "FsAutoComplete breaks spec and and returns error instead of empty list."
   (if (eq major-mode 'fsharp-mode)
       (condition-case err
           (cl-call-next-method)
         (jsonrpc-error
-         (when (equal (cadddr err) '(jsonrpc-error-message . "Could not find declaration"))
-           nil)))
+         (not (equal (cadddr err) '(jsonrpc-error-message . "Could not find declaration")))))
     (when (cl-next-method-p)
       (cl-call-next-method))))
 

From bd0c43b340541d5d1faffefdaeaa93c3f6e5e45a Mon Sep 17 00:00:00 2001
From: JenChieh <jcs090218@gmail.com>
Date: Fri, 15 Jan 2021 15:02:33 +0800
Subject: [PATCH 046/147] Fixed package lint

---
 eglot-fsharp.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 11b4d87..2abc695 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -3,8 +3,10 @@
 ;; Copyright (C) 2019-2021  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@archlinux.org>
-;; Package-Requires: ((eglot "1.4") (fsharp-mode "1.10"))
+;; Package-Requires: ((emacs "27.1") (eglot "1.4") (fsharp-mode "1.10"))
+;; Version: 1.10
 ;; Keywords: languages
+;; URL: https://github.com/fsharp/emacs-fsharp-mode
 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by

From 1c71dfa0b182f1b466db71dcf73c984b65340ac4 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 15 Jan 2021 18:13:13 +0100
Subject: [PATCH 047/147] Relax version restriction to 26.3 (minimum version
 tested)

---
 eglot-fsharp.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 2abc695..956b649 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2021  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@archlinux.org>
-;; Package-Requires: ((emacs "27.1") (eglot "1.4") (fsharp-mode "1.10"))
+;; Package-Requires: ((emacs "26.3") (eglot "1.4") (fsharp-mode "1.10"))
 ;; Version: 1.10
 ;; Keywords: languages
 ;; URL: https://github.com/fsharp/emacs-fsharp-mode

From 8987dbcd7b1114d2da9bba6fa2b1b7ca8ba98999 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 15 Jan 2021 19:10:05 +0100
Subject: [PATCH 048/147] Bump version

Fixes package-lint error:

eglot-fsharp.el:6:52 (package-lint-warning) Version dependency for fsharp-mode appears too high: try 1.9.15
---
 fsharp-mode.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index 4b28966..61d7960 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -9,7 +9,7 @@
 ;; Maintainer: Jürgen Hötzel
 ;; Package-Requires: ((emacs "25")  (s "1.3.1") (eglot))
 ;; Keywords: languages
-;; Version: 1.9.15
+;; Version: 1.11-snapshot
 
 ;; This file is not part of GNU Emacs.
 

From 8a915c64197caa63f4a4e31d11bd25129838a627 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 24 Jan 2021 12:51:13 +0100
Subject: [PATCH 049/147] Fix typo

---
 eglot-fsharp.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 956b649..20829b4 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -1,4 +1,4 @@
-;;; eglot-fsharp.el --- Lua eglot integration                     -*- lexical-binding: t; -*-
+;;; eglot-fsharp.el --- fsharp-mode eglot integration                     -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 2019-2021  Jürgen Hötzel
 

From ae9aacf48ff0523a643270f6b4131799fb17c055 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 24 Jan 2021 13:00:08 +0100
Subject: [PATCH 050/147] Fix typo in License file

---
 LICENSE.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LICENSE.md b/LICENSE.md
index 064244c..0e749dc 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -2,7 +2,7 @@ Copyright 2011-2015
 
 
     Robin Neatherway
-    Jurgen Hurtzel
+    Jürgen Hötzel
     Jason Imison
     Chris Barrett
 

From 906cf4bd85951130a686e6cfc8b9eef40627b2f5 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 24 Jan 2021 13:18:09 +0100
Subject: [PATCH 051/147] Use correct (github compatible) license file format

---
 LICENSE    | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++
 LICENSE.md | 208 -----------------------------------------------------
 2 files changed, 202 insertions(+), 208 deletions(-)
 create mode 100644 LICENSE
 delete mode 100644 LICENSE.md

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/LICENSE.md b/LICENSE.md
deleted file mode 100644
index 0e749dc..0000000
--- a/LICENSE.md
+++ /dev/null
@@ -1,208 +0,0 @@
-Copyright 2011-2015
-
-
-    Robin Neatherway
-    Jürgen Hötzel
-    Jason Imison
-    Chris Barrett
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-------------------------------------------------------------
-
-Apache License, Version 2.0
-===========================
-
-Apache License   
-Version 2.0, January 2004    
-http://www.apache.org/licenses/    
-
-### TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-
-**1. Definitions.**
-
- - "License" shall mean the terms and conditions for use, reproduction,
-and distribution as defined by Sections 1 through 9 of this document.
-
- - "Licensor" shall mean the copyright owner or entity authorized by
-the copyright owner that is granting the License.
-
- - "Legal Entity" shall mean the union of the acting entity and all
-other entities that control, are controlled by, or are under common
-control with that entity. For the purposes of this definition,
-"control" means (i) the power, direct or indirect, to cause the
-direction or management of such entity, whether by contract or
-otherwise, or (ii) ownership of fifty percent (50%) or more of the
-outstanding shares, or (iii) beneficial ownership of such entity.
-
- - "You" (or "Your") shall mean an individual or Legal Entity
-exercising permissions granted by this License.
-
- - "Source" form shall mean the preferred form for making modifications,
-including but not limited to software source code, documentation
-source, and configuration files.
-
- - "Object" form shall mean any form resulting from mechanical
-transformation or translation of a Source form, including but
-not limited to compiled object code, generated documentation,
-and conversions to other media types.
-
- - "Work" shall mean the work of authorship, whether in Source or
-Object form, made available under the License, as indicated by a
-copyright notice that is included in or attached to the work
-(an example is provided in the Appendix below).
-
- - "Derivative Works" shall mean any work, whether in Source or Object
-form, that is based on (or derived from) the Work and for which the
-editorial revisions, annotations, elaborations, or other modifications
-represent, as a whole, an original work of authorship. For the purposes
-of this License, Derivative Works shall not include works that remain
-separable from, or merely link (or bind by name) to the interfaces of,
-the Work and Derivative Works thereof.
-
- - "Contribution" shall mean any work of authorship, including
-the original version of the Work and any modifications or additions
-to that Work or Derivative Works thereof, that is intentionally
-submitted to Licensor for inclusion in the Work by the copyright owner
-or by an individual or Legal Entity authorized to submit on behalf of
-the copyright owner. For the purposes of this definition, "submitted"
-means any form of electronic, verbal, or written communication sent
-to the Licensor or its representatives, including but not limited to
-communication on electronic mailing lists, source code control systems,
-and issue tracking systems that are managed by, or on behalf of, the
-Licensor for the purpose of discussing and improving the Work, but
-excluding communication that is conspicuously marked or otherwise
-designated in writing by the copyright owner as "Not a Contribution."
-
- - "Contributor" shall mean Licensor and any individual or Legal Entity
-on behalf of whom a Contribution has been received by Licensor and
-subsequently incorporated within the Work.
-
-**2. Grant of Copyright License.**
-Subject to the terms and conditions of
-this License, each Contributor hereby grants to You a perpetual,
-worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-copyright license to reproduce, prepare Derivative Works of,
-publicly display, publicly perform, sublicense, and distribute the
-Work and such Derivative Works in Source or Object form.
-
-**3. Grant of Patent License.**
-Subject to the terms and conditions of
-this License, each Contributor hereby grants to You a perpetual,
-worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-(except as stated in this section) patent license to make, have made,
-use, offer to sell, sell, import, and otherwise transfer the Work,
-where such license applies only to those patent claims licensable
-by such Contributor that are necessarily infringed by their
-Contribution(s) alone or by combination of their Contribution(s)
-with the Work to which such Contribution(s) was submitted. If You
-institute patent litigation against any entity (including a
-cross-claim or counterclaim in a lawsuit) alleging that the Work
-or a Contribution incorporated within the Work constitutes direct
-or contributory patent infringement, then any patent licenses
-granted to You under this License for that Work shall terminate
-as of the date such litigation is filed.
-
-**4. Redistribution.**
-You may reproduce and distribute copies of the
-Work or Derivative Works thereof in any medium, with or without
-modifications, and in Source or Object form, provided that You
-meet the following conditions:
-
- - You must give any other recipients of the Work or
-    Derivative Works a copy of this License; and
- 
- - You must cause any modified files to carry prominent notices
-    stating that You changed the files; and
-
- - You must retain, in the Source form of any Derivative Works
-    that You distribute, all copyright, patent, trademark, and
-    attribution notices from the Source form of the Work,
-    excluding those notices that do not pertain to any part of
-    the Derivative Works; and
-
- - If the Work includes a "NOTICE" text file as part of its
-    distribution, then any Derivative Works that You distribute must
-    include a readable copy of the attribution notices contained
-    within such NOTICE file, excluding those notices that do not
-    pertain to any part of the Derivative Works, in at least one
-    of the following places: within a NOTICE text file distributed
-    as part of the Derivative Works; within the Source form or
-    documentation, if provided along with the Derivative Works; or,
-    within a display generated by the Derivative Works, if and
-    wherever such third-party notices normally appear. The contents
-    of the NOTICE file are for informational purposes only and
-    do not modify the License. You may add Your own attribution
-    notices within Derivative Works that You distribute, alongside
-    or as an addendum to the NOTICE text from the Work, provided
-    that such additional attribution notices cannot be construed
-    as modifying the License.
-
-You may add Your own copyright statement to Your modifications and
-may provide additional or different license terms and conditions
-for use, reproduction, or distribution of Your modifications, or
-for any such Derivative Works as a whole, provided Your use,
-reproduction, and distribution of the Work otherwise complies with
-the conditions stated in this License.
-
-**5. Submission of Contributions.**
-Unless You explicitly state otherwise,
-any Contribution intentionally submitted for inclusion in the Work
-by You to the Licensor shall be under the terms and conditions of
-this License, without any additional terms or conditions.
-Notwithstanding the above, nothing herein shall supersede or modify
-the terms of any separate license agreement you may have executed
-with Licensor regarding such Contributions.
-
-**6. Trademarks.**
-This License does not grant permission to use the trade
-names, trademarks, service marks, or product names of the Licensor,
-except as required for reasonable and customary use in describing the
-origin of the Work and reproducing the content of the NOTICE file.
-
-**7. Disclaimer of Warranty.**
-Unless required by applicable law or
-agreed to in writing, Licensor provides the Work (and each
-Contributor provides its Contributions) on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-implied, including, without limitation, any warranties or conditions
-of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-PARTICULAR PURPOSE. You are solely responsible for determining the
-appropriateness of using or redistributing the Work and assume any
-risks associated with Your exercise of permissions under this License.
-
-**8. Limitation of Liability.**
-In no event and under no legal theory,
-whether in tort (including negligence), contract, or otherwise,
-unless required by applicable law (such as deliberate and grossly
-negligent acts) or agreed to in writing, shall any Contributor be
-liable to You for damages, including any direct, indirect, special,
-incidental, or consequential damages of any character arising as a
-result of this License or out of the use or inability to use the
-Work (including but not limited to damages for loss of goodwill,
-work stoppage, computer failure or malfunction, or any and all
-other commercial damages or losses), even if such Contributor
-has been advised of the possibility of such damages.
-
-**9. Accepting Warranty or Additional Liability.**
-While redistributing
-the Work or Derivative Works thereof, You may choose to offer,
-and charge a fee for, acceptance of support, warranty, indemnity,
-or other liability obligations and/or rights consistent with this
-License. However, in accepting such obligations, You may act only
-on Your own behalf and on Your sole responsibility, not on behalf
-of any other Contributor, and only if You agree to indemnify,
-defend, and hold each Contributor harmless for any liability
-incurred by, or claims asserted against, such Contributor by reason
-of your accepting any such warranty or additional liability.

From 303caa4023f56f647421d809eb240126225dd182 Mon Sep 17 00:00:00 2001
From: Kien Nguyen <kien.n.quang@gmail.com>
Date: Wed, 28 Oct 2020 09:19:18 +0900
Subject: [PATCH 052/147] fsharp-mode: do not explicitly depend on eglot

---
 Cask           | 3 ++-
 fsharp-mode.el | 4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/Cask b/Cask
index dc1eaf7..35803d5 100644
--- a/Cask
+++ b/Cask
@@ -5,5 +5,6 @@
 (files "*.el")
 ;; FIXME: Use multiple packages: https://github.com/melpa/melpa#example-multiple-packages-in-one-repository ?
 (development
- (depends-on "buttercup"))
+ (depends-on "buttercup")
+ (depends-on "eglot"))
 
diff --git a/fsharp-mode.el b/fsharp-mode.el
index 61d7960..0263a36 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -5,9 +5,9 @@
 ;; Author: 1993-1997 Xavier Leroy, Jacques Garrigue and Ian T Zimmerman
 ;;         2010-2011 Laurent Le Brun <laurent@le-brun.eu>
 ;;         2012-2014 Robin Neatherway <robin.neatherway@gmail.com>
-;;         2017-2019 Jürgen Hötzel
+;;         2017-2021 Jürgen Hötzel
 ;; Maintainer: Jürgen Hötzel
-;; Package-Requires: ((emacs "25")  (s "1.3.1") (eglot))
+;; Package-Requires: ((emacs "25")  (s "1.3.1"))
 ;; Keywords: languages
 ;; Version: 1.11-snapshot
 

From b6095e08ff228388cc7a07885ddc92d742047610 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 24 Jan 2021 14:52:24 +0100
Subject: [PATCH 053/147] Document the eglot packet-split

Refs #253.
---
 README.org | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/README.org b/README.org
index 13fa47a..a36d69d 100644
--- a/README.org
+++ b/README.org
@@ -14,10 +14,10 @@ Provides support for the F# language in Emacs. Includes the following features:
   - Jump to definition [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html][Find Identifier References]] (Xref)
 
 ** LSP mode
-Previous versions of =fsharp-mode= (mis)used a second repository [[https://github.com/rneatherway/emacs-fsharp-mode-bin][emacs-fsharp-mode-bin]] to distribute =fsautocomplete.exe= and =fsharp-mode= together.
 
-The current version of =fsharp-mode= installs =fsautocomplete.exe= automatically via [[https://github.com/joaotavora/eglot][eglot-fsharp]] (part of this repo) or
-[[https://github.com/emacs-lsp/lsp-mode][lsp-mode]] (untested).
+The current version of =fsharp-mode= installs =fsautocomplete.exe=
+automatically via =eglot-fsharp.el= (part of this mono repo, [[https://melpa.org/#/eglot-fsharp][eglot-fsharp
+on melpa]]) or [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]] (untested).
 
 =fsharp-mode= is tested with Emacs 26.1+ and NET Core 2.1 (LTS)
 
@@ -62,10 +62,9 @@ I recommend to use [[https://cask.github.io/why-cask.html][Cask]]. Add this to y
 
 ** Eglot integration
 
-=eglot-fsharp= is part of this package and provides integration to [[https://github.com/joaotavora/eglot][Eglot]] Emacs LSP client:
+The =eglot-fsharp= integration is not part of [[https://melpa.org/#/fsharp-mode][fsharp-mode on melpa]].
 
-   - Automatic =fsautocomplete= download
-   - Workaround for non-LSP standard-compliant
+It is available via the seperate package [[https://melpa.org/#/eglot-fsharp][eglot-fsharp on melpa]].
 
 Add to your config:
 #+BEGIN_SRC elisp

From 95572ededaedc03997c7c59cdf0d6a4b33ff28c5 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 26 Jan 2021 05:46:53 +0100
Subject: [PATCH 054/147] Fix remaining package-lint errors: add jsonrpc
 explicitly

---
 eglot-fsharp.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 20829b4..39e6758 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2021  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@archlinux.org>
-;; Package-Requires: ((emacs "26.3") (eglot "1.4") (fsharp-mode "1.10"))
+;; Package-Requires: ((emacs "26.3") (eglot "1.4") (fsharp-mode "1.10") (jsonrpc "1.0.14"))
 ;; Version: 1.10
 ;; Keywords: languages
 ;; URL: https://github.com/fsharp/emacs-fsharp-mode

From 05a2c6a441d09501b81db382b18060fdd8540774 Mon Sep 17 00:00:00 2001
From: Shohei YOSHIDA <syohex@gmail.com>
Date: Tue, 26 Jan 2021 22:58:12 +0900
Subject: [PATCH 055/147] Replace dash functions and fix byte-compile warnings

---
 fsharp-mode-util.el | 43 +++++++++++++++++++++++--------------------
 fsharp-mode.el      |  4 +++-
 2 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/fsharp-mode-util.el b/fsharp-mode-util.el
index daa65fb..d20106a 100644
--- a/fsharp-mode-util.el
+++ b/fsharp-mode-util.el
@@ -1,4 +1,4 @@
-;;; fsharp-mode-util.el --- utility functions
+;;; fsharp-mode-util.el --- utility functions -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2015 Robin Neatherway
 
@@ -23,10 +23,10 @@
 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 ;; Boston, MA 02110-1301, USA.
 
-(with-no-warnings (require 'cl))
+(require 'cl-lib)
 
 (defvar fsharp-ac-using-mono
-  (case system-type
+  (cl-case system-type
     ((windows-nt cygwin msdos) nil)
     (otherwise t))
   "Whether the .NET runtime in use is mono.
@@ -35,36 +35,39 @@ for all *nix.")
 
 (defun fsharp-mode--program-files-x86 ()
   (file-name-as-directory
-   (car (-drop-while 'not
-                     (list (getenv "ProgramFiles(x86)")
-                           (getenv "ProgramFiles")
-                           "C:\\Program Files (x86)")))))
+   (or (getenv "ProgramFiles(x86)")
+       (getenv "ProgramFiles")
+       "C:\\Program Files (x86)")))
 
 (defun fsharp-mode--vs2017-msbuild-find (exe)
   "Return EXE absolute path for Visual Studio 2017, if existent, else nil."
-  (->> (--map (concat (fsharp-mode--program-files-x86)
-                      "Microsoft Visual Studio/2017/"
-                      it
-                      "msbuild/15.0/bin/"
-                      exe)
-              '("Enterprise/" "Professional/" "Community/" "BuildTools/"))
-       (--first (file-executable-p it))))
+  (let ((candidates (mapcar (lambda (edition)
+                              (concat (fsharp-mode--program-files-x86)
+                                      edition
+                                      "msbuild/15.0/bin/"
+                                      exe))
+                            '("Enterprise/" "Professional/"
+                              "Community/" "BuildTools/"))))
+    (cl-find-if (lambda (exe) (file-executable-p exe)) candidates)))
 
 (defun fsharp-mode--msbuild-find (exe)
   (if fsharp-ac-using-mono
       (executable-find exe)
-    (let* ((searchdirs (--map (concat (fsharp-mode--program-files-x86)
-                                      "MSBuild/" it "/Bin")
-                              '("14.0" "13.0" "12.0")))
+    (let* ((searchdirs (mapcar (lambda (ver)
+                                 (concat (fsharp-mode--program-files-x86)
+                                         "MSBuild/" ver "/Bin"))
+                               '("14.0" "13.0" "12.0")))
            (exec-path (append searchdirs exec-path)))
       (or (fsharp-mode--vs2017-msbuild-find exe) (executable-find exe)))))
 
 (defun fsharp-mode--executable-find (exe)
   (if fsharp-ac-using-mono
       (executable-find exe)
-    (let* ((searchdirs (--map (concat (fsharp-mode--program-files-x86)
-                                      "Microsoft SDKs/F#/" it "/Framework/v4.0")
-                              '("10.1" "4.0" "3.1" "3.0")))
+    (let* ((searchdirs (mapcar (lambda (ver)
+                                 (concat (fsharp-mode--program-files-x86)
+                                         "Microsoft SDKs/F#/"
+                                         ver "/Framework/v4.0"))
+                               '("10.1" "4.0" "3.1" "3.0")))
            (exec-path (append searchdirs exec-path)))
       (executable-find exe))))
 
diff --git a/fsharp-mode.el b/fsharp-mode.el
index 0263a36..a060e4a 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -35,6 +35,8 @@
 (require 'fsharp-mode-util)
 (require 'compile)
 (require 'project)
+(require 'subr-x)
+(require 'seq)
 
 (defgroup fsharp nil
   "Support for the Fsharp programming language, <http://www.fsharp.net/>"
@@ -358,7 +360,7 @@ folders relative to DIR-OR-FILE."
 
 ;; Make project.el aware of fsharp projects
 (defun fsharp-mode-project-root (dir)
-  (-when-let (project-file (fsharp-mode/find-sln-or-fsproj dir))
+  (when-let (project-file (fsharp-mode/find-sln-or-fsproj dir))
     (cons 'fsharp (file-name-directory project-file))))
 
 (cl-defmethod project-roots ((project (head fsharp)))

From caacbe523eeaf4588e0123cb191224c27f31cbb6 Mon Sep 17 00:00:00 2001
From: Rafal Gwozdzinski <rafal.gwozdzinski@gmail.com>
Date: Sun, 31 Jan 2021 09:42:00 +0100
Subject: [PATCH 056/147] New defcustom: `fsharp-autosave-on-file-load':
 Optional autosave
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Jürgen Hötzel <juergen@hoetzel.info>
---
 fsharp-mode.el | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index a060e4a..183b65d 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -171,6 +171,13 @@
 (defvar fsharp-mode-hook nil
   "Hook for fsharp-mode")
 
+(defcustom fsharp-autosave-on-file-load nil
+  "Determine if buffer should be automatically saved on
+`fsharp-load-buffer-file'.
+If set to t, the buffer will always be saved, silently."
+  :type 'boolean
+  :group 'fsharp-mode)
+
 ;;;###autoload
 (define-derived-mode fsharp-mode prog-mode "fsharp"
   :syntax-table fsharp-mode-syntax-table
@@ -290,10 +297,11 @@
   (require 'inf-fsharp-mode)
   (let* ((name buffer-file-name)
          (command (concat "#load \"" name "\"")))
-    (when (buffer-modified-p)
-      (when (y-or-n-p (concat "Do you want to save \"" name "\" before
-loading it? "))
-        (save-buffer)))
+    (when (and (buffer-modified-p)
+	       (or fsharp-autosave-on-file-load
+		   (y-or-n-p (concat "Do you want to save \"" name
+				     "\" before loading it? "))))
+      (save-buffer))
     (fsharp-run-process-if-needed)
     (fsharp-simple-send inferior-fsharp-buffer-name command)))
 

From 955cb168781a4b7c36a3fa16fd6b98b74f64c772 Mon Sep 17 00:00:00 2001
From: Rafal Gwozdzinski <rafal.gwozdzinski@gmail.com>
Date: Sun, 31 Jan 2021 16:27:31 +0100
Subject: [PATCH 057/147] Generic face for custom operators that contain pipe
 char sequence.

---
 fsharp-mode-font.el | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/fsharp-mode-font.el b/fsharp-mode-font.el
index a063919..d77e463 100644
--- a/fsharp-mode-font.el
+++ b/fsharp-mode-font.el
@@ -171,6 +171,17 @@ with initial value INITVALUE and optional DOCSTRING."
   "<|\\{1,3\\}\\||\\{1,3\\}>"
   "Match the full range of pipe operators -- |>, ||>, |||>, etc.")
 
+(def-fsharp-compiled-var fsharp-custom-operator-with-pipe-regexp
+  (let ((op-chars "!%&\\*\\+\\-\\./<=>@\\^~") ;; all F# custom operator chars except for `|`
+        (backward-pipe "<|\\{1,3\\}")
+        (forward-pipe "|\\{1,3\\}>")
+        (alt "\\|"))
+    (concat "[" op-chars "|]*" backward-pipe "[" op-chars  "]+"
+        alt "[" op-chars "|]+" backward-pipe "[" op-chars  "]*"
+        alt "[" op-chars  "]*" forward-pipe  "[" op-chars "|]+"
+        alt "[" op-chars  "]+" forward-pipe  "[" op-chars "|]*"))
+  "Match operators that contains pipe sequence -- <|>, |>>, <<|, etc.")
+
 (def-fsharp-compiled-var fsharp-operator-case-regexp
   "\\s-+\\(|\\)[A-Za-z0-9_' ]"
   "Match literal | in contexts like match and type declarations.")
@@ -297,6 +308,7 @@ with initial value INITVALUE and optional DOCSTRING."
         nil nil
         (1 font-lock-function-name-face)
         (2 'fsharp-ui-operator-face)))
+      (,fsharp-custom-operator-with-pipe-regexp . 'fsharp-ui-generic-face)
       (,fsharp-operator-pipe-regexp . 'fsharp-ui-operator-face)
       (,fsharp-member-function-regexp 1 font-lock-function-name-face)
       (,fsharp-overload-operator-regexp 1 font-lock-function-name-face)

From 58f49aebc2d34fdcda1d04ee31418029885b23f8 Mon Sep 17 00:00:00 2001
From: Rafal Gwozdzinski <rafal.gwozdzinski@gmail.com>
Date: Wed, 3 Feb 2021 06:32:57 +0100
Subject: [PATCH 058/147] Add font tests

---
 test/fsharp-mode-font-tests.el | 44 ++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 test/fsharp-mode-font-tests.el

diff --git a/test/fsharp-mode-font-tests.el b/test/fsharp-mode-font-tests.el
new file mode 100644
index 0000000..14a2174
--- /dev/null
+++ b/test/fsharp-mode-font-tests.el
@@ -0,0 +1,44 @@
+;;; fsharp-mode-font-tests.el ---                         -*- lexical-binding: t; -*-
+
+(require 'buttercup)
+
+(require 'fsharp-mode)
+(require 'fsharp-mode-font)
+
+(defmacro with-highlighted (src &rest body)
+  "Insert SRC in a temporary fsharp-mode buffer, apply syntax highlighting,
+then run BODY."
+  `(with-temp-buffer
+     (fsharp-mode)
+     (insert ,src)
+     (goto-char (point-min))
+     ;; Ensure we've syntax-highlighted the whole buffer.
+     (if (fboundp 'font-lock-ensure)
+         (font-lock-ensure)
+       (with-no-warnings
+         (font-lock-fontify-buffer)))
+     ,@body))
+
+(defun str-face (op)
+  (goto-char (point-min))
+  (search-forward op)
+  (left-char)
+  (face-at-point))
+
+(describe "When locking operators"
+  (it "uses ui operator face for pipes"
+    (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
+      (should (eq (str-face "|>") 'fsharp-ui-operator-face))
+      (should (eq (str-face "||>") 'fsharp-ui-operator-face))
+      (should (eq (str-face "|||>") 'fsharp-ui-operator-face))
+      (should (eq (str-face "<|") 'fsharp-ui-operator-face))
+      (should (eq (str-face "<||") 'fsharp-ui-operator-face))
+      (should (eq (str-face "<|||") 'fsharp-ui-operator-face)))))
+
+(describe "When locking operators"
+  (it "uses ui generic face for custom operators containing pipes"
+    (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
+      (should (eq (str-face "<<|") 'fsharp-ui-generic-face))
+      (should (eq (str-face "|>>") 'fsharp-ui-generic-face))
+      (should (eq (str-face "<|>") 'fsharp-ui-generic-face))
+      (should (eq (str-face "<<|!") 'fsharp-ui-generic-face)))))

From 20db4460656f1e859b1dd084158205ed6121aeef Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 28 Mar 2021 17:26:33 +0200
Subject: [PATCH 059/147] Add Emacs 27.2 to build matrix

---
 .github/workflows/test.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4b9675f..9395e97 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -14,6 +14,7 @@ jobs:
         emacs_version:
           - 26.3
           - 27.1
+          - 27.2
           - snapshot
     steps:
     - uses: purcell/setup-emacs@master

From 0461fc401229fecf61b4820237ddcbeb8b05e9e9 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Mon, 29 Mar 2021 22:46:51 +0200
Subject: [PATCH 060/147] Fix invalid unix permissions of fsautocomplete

Workaround for FAKE issue:
https://github.com/fsharp/FsAutoComplete/issues/715
---
 eglot-fsharp.el | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 39e6758..752a391 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -124,7 +124,12 @@
       (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
         (unless (zerop (call-process "unzip" nil nil nil "-o" zip))
           (error "Failed to unzip %s" zip))
-        (delete-file zip)))))
+	(unless (eq system-type 'windows-nt)
+	  (dolist  (file (directory-files-recursively (file-name-directory (eglot-fsharp--path-to-server)) "." t))
+	    (if (file-directory-p file)
+		(chmod file #o755)
+	      (chmod file #o644)))))
+        (delete-file zip))))
 
  ;;;###autoload
 (defun eglot-fsharp (interactive)

From 41eb84a3c70600195966b17b725de6a95d864a9a Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 30 Mar 2021 16:30:09 +0200
Subject: [PATCH 061/147] Adapt the tests to the latest fsautocomplete version

The jump to definition in pervasives is now available.
---
 test/integration-tests.el | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index d3bec19..05a6391 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -63,17 +63,13 @@
       (eglot-fsharp--sniff-diagnostics)
       (completion-at-point)
       (expect (looking-back "X\\.func") :to-be t)))
-  (it "doesn't throw error when definition does not exist"
+  (it "finds definition in pervasives"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
       (eglot-fsharp--sniff-diagnostics)
       (goto-char 253)
       (expect (current-word) :to-equal "printfn") ;sanity check
-      (expect
-       (condition-case err
-	   (call-interactively #'xref-find-definitions)
-	 (user-error
-	  (cadr err)))
-       :to-equal "No definitions found for: LSP identifier at point.")))
+      (call-interactively #'xref-find-definitions)
+      (expect (file-name-nondirectory (buffer-file-name)) :to-equal "fslib-extra-pervasives.fs")))
   (it "finds definitions in other files of Project"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
       (goto-char 150)

From 0be5080eff1a839b6d4add8f3245dbf73f4d3f5c Mon Sep 17 00:00:00 2001
From: Keith Pinson <keith.pinson@banno.com>
Date: Wed, 31 Mar 2021 12:19:13 -0400
Subject: [PATCH 062/147] fix: `//`-comments filled incorrectly (`//` not
 acting as prefix)

The problem is described
[here](https://github.com/syl20bnr/spacemacs/issues/11326). I haven't been
writing much F# lately but I found that `emacs-scala-mode` has the same problem
and this fix works well for it, so I thought I would submit it here too.
---
 fsharp-mode.el | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index 183b65d..fd5fe13 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -218,6 +218,7 @@ If set to t, the buffer will always be saved, silently."
         comment-end              ""
         comment-column           40
         comment-start-skip       "///* *"
+        adaptive-fill-regexp     "[ \t]*\\(//+[ \t]*\\)*"
         comment-indent-function  'fsharp-comment-indent-function
         indent-region-function   'fsharp-indent-region
         indent-line-function     'fsharp-indent-line

From 93b1fbc31d73286a18640a36fc2be87d1736e0f2 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Wed, 31 Mar 2021 21:31:37 +0200
Subject: [PATCH 063/147] Make `adaptive-fill-regexp` buffer-local

This prevents effects on other major modes depending on the Emacs
default.
---
 fsharp-mode.el | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index fd5fe13..c8e0153 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -201,6 +201,7 @@ If set to t, the buffer will always be saved, silently."
           comment-column
           comment-start-skip
           comment-indent-function
+          adaptive-fill-regexp
           parse-sexp-ignore-comments
           indent-region-function
           indent-line-function

From 38eccc8d082964d58573fb4c9f9475ff488ed9e5 Mon Sep 17 00:00:00 2001
From: Rafal Gwozdzinski <rafal.gwozdzinski@gmail.com>
Date: Fri, 6 Aug 2021 10:13:54 +0200
Subject: [PATCH 064/147] Fix operator font tests

---
 test/fsharp-mode-font-tests.el | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/test/fsharp-mode-font-tests.el b/test/fsharp-mode-font-tests.el
index 14a2174..55397f4 100644
--- a/test/fsharp-mode-font-tests.el
+++ b/test/fsharp-mode-font-tests.el
@@ -1,9 +1,7 @@
 ;;; fsharp-mode-font-tests.el ---                         -*- lexical-binding: t; -*-
 
 (require 'buttercup)
-
 (require 'fsharp-mode)
-(require 'fsharp-mode-font)
 
 (defmacro with-highlighted (src &rest body)
   "Insert SRC in a temporary fsharp-mode buffer, apply syntax highlighting,
@@ -22,23 +20,23 @@ then run BODY."
 (defun str-face (op)
   (goto-char (point-min))
   (search-forward op)
-  (left-char)
+  (left-char 2)
   (face-at-point))
 
 (describe "When locking operators"
   (it "uses ui operator face for pipes"
     (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
-      (should (eq (str-face "|>") 'fsharp-ui-operator-face))
-      (should (eq (str-face "||>") 'fsharp-ui-operator-face))
-      (should (eq (str-face "|||>") 'fsharp-ui-operator-face))
-      (should (eq (str-face "<|") 'fsharp-ui-operator-face))
-      (should (eq (str-face "<||") 'fsharp-ui-operator-face))
-      (should (eq (str-face "<|||") 'fsharp-ui-operator-face)))))
+      (should (equal (str-face " |> ") 'fsharp-ui-operator-face))
+      (should (equal (str-face " ||> ") 'fsharp-ui-operator-face))
+      (should (equal (str-face " |||> ") 'fsharp-ui-operator-face))
+      (should (equal (str-face " <| ") 'fsharp-ui-operator-face))
+      (should (equal (str-face " <|| ") 'fsharp-ui-operator-face))
+      (should (equal (str-face " <||| ") 'fsharp-ui-operator-face)))))
 
 (describe "When locking operators"
   (it "uses ui generic face for custom operators containing pipes"
     (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
-      (should (eq (str-face "<<|") 'fsharp-ui-generic-face))
-      (should (eq (str-face "|>>") 'fsharp-ui-generic-face))
-      (should (eq (str-face "<|>") 'fsharp-ui-generic-face))
-      (should (eq (str-face "<<|!") 'fsharp-ui-generic-face)))))
+      (should (equal (str-face "<<| ") 'fsharp-ui-generic-face))
+      (should (equal (str-face " |>> ") 'fsharp-ui-generic-face))
+      (should (equal (str-face " <|> ") 'fsharp-ui-generic-face))
+      (should (equal (str-face " <<|!") 'fsharp-ui-generic-face)))))

From d5800d8a796d8e3c716b383d34e52818e0242ea6 Mon Sep 17 00:00:00 2001
From: Johan von Tangen Sivertsen <johanvts@gmail.com>
Date: Mon, 4 Oct 2021 09:24:19 +0200
Subject: [PATCH 065/147] Update README.org

Add some hints on how to use completions and go-to-reference.
---
 README.org | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.org b/README.org
index a36d69d..93a1b09 100644
--- a/README.org
+++ b/README.org
@@ -73,6 +73,8 @@ Add to your config:
 
 and execute =M-x eglot=
 
+With eglot running use `xref-find-definitions` (bound to =M-.= pr. default) to go to definition. Completions are accessable via. `completion-at-point` (or a completion backend ex. company-mode [[https://melpa.org/#/company]])
+
 
 ** Projects
 

From 074ba9917e2ae33086835ea08c79e36990a44ece Mon Sep 17 00:00:00 2001
From: Naoya Yamashita <conao3@gmail.com>
Date: Wed, 20 Oct 2021 02:01:16 +0900
Subject: [PATCH 066/147] remove unneeded `files` directive

(files "*.el") is not needed.

Before this commit:
    $ cask files
    eglot-fsharp.el
    fsharp-mode-font.el
    fsharp-mode-structure.el
    fsharp-mode-util.el
    fsharp-mode.el
    inf-fsharp-mode.el

After this commit:
    $ cask files
    eglot-fsharp.el
    fsharp-mode-font.el
    fsharp-mode-structure.el
    fsharp-mode-util.el
    fsharp-mode.el
    inf-fsharp-mode.el
---
 Cask | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Cask b/Cask
index 35803d5..cc6c144 100644
--- a/Cask
+++ b/Cask
@@ -2,9 +2,8 @@
 (source melpa)
 
 (package-file "fsharp-mode.el")
-(files "*.el")
+
 ;; FIXME: Use multiple packages: https://github.com/melpa/melpa#example-multiple-packages-in-one-repository ?
 (development
  (depends-on "buttercup")
  (depends-on "eglot"))
-

From cbd48f448b4e5b42c2c04d4608c3b50a60ed2256 Mon Sep 17 00:00:00 2001
From: Naoya Yamashita <conao3@gmail.com>
Date: Wed, 20 Oct 2021 02:10:33 +0900
Subject: [PATCH 067/147] fix indentation

---
 eglot-fsharp.el     |  2 +-
 fsharp-mode-font.el | 12 +++++-------
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 752a391..3d8069f 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -129,7 +129,7 @@
 	    (if (file-directory-p file)
 		(chmod file #o755)
 	      (chmod file #o644)))))
-        (delete-file zip))))
+      (delete-file zip))))
 
  ;;;###autoload
 (defun eglot-fsharp (interactive)
diff --git a/fsharp-mode-font.el b/fsharp-mode-font.el
index d77e463..648e90d 100644
--- a/fsharp-mode-font.el
+++ b/fsharp-mode-font.el
@@ -177,9 +177,9 @@ with initial value INITVALUE and optional DOCSTRING."
         (forward-pipe "|\\{1,3\\}>")
         (alt "\\|"))
     (concat "[" op-chars "|]*" backward-pipe "[" op-chars  "]+"
-        alt "[" op-chars "|]+" backward-pipe "[" op-chars  "]*"
-        alt "[" op-chars  "]*" forward-pipe  "[" op-chars "|]+"
-        alt "[" op-chars  "]+" forward-pipe  "[" op-chars "|]*"))
+            alt "[" op-chars "|]+" backward-pipe "[" op-chars  "]*"
+            alt "[" op-chars  "]*" forward-pipe  "[" op-chars "|]+"
+            alt "[" op-chars  "]+" forward-pipe  "[" op-chars "|]*"))
   "Match operators that contains pipe sequence -- <|>, |>>, <<|, etc.")
 
 (def-fsharp-compiled-var fsharp-operator-case-regexp
@@ -382,16 +382,14 @@ with initial value INITVALUE and optional DOCSTRING."
                                    'syntax-table (string-to-syntax "."))
                 (put-text-property (match-beginning 0) (match-end 0)
                                    'syntax-table (string-to-syntax "|"))
-                nil)))
-        )
+                nil))))
 
        (t ; Then we are in a triple-quoted string
         (when (re-search-forward "\"\"\"" end 'move)
           (put-text-property (- (match-beginning 0) 1) (match-beginning 0)
                              'syntax-table (string-to-syntax "."))
           (put-text-property (match-beginning 0) (match-end 0)
-                             'syntax-table (string-to-syntax "|")))
-        )))))
+                             'syntax-table (string-to-syntax "|"))))))))
 
 (provide 'fsharp-mode-font)
 

From 0e713614c3020813a3df6b81a9ded2ea5a40e5ec Mon Sep 17 00:00:00 2001
From: Naoya Yamashita <conao3@gmail.com>
Date: Wed, 20 Oct 2021 02:10:47 +0900
Subject: [PATCH 068/147] fix closing paren

---
 fsharp-mode-structure.el | 33 ++++++++++-----------------------
 inf-fsharp-mode.el       |  4 +---
 2 files changed, 11 insertions(+), 26 deletions(-)

diff --git a/fsharp-mode-structure.el b/fsharp-mode-structure.el
index 4d913e0..2fb1a04 100644
--- a/fsharp-mode-structure.el
+++ b/fsharp-mode-structure.el
@@ -285,8 +285,7 @@ to scan."
   "Returns non-nil if the current line should dedent one level."
   (save-excursion
     (progn (back-to-indentation)
-           (looking-at fsharp-outdent-re))
-    ))
+           (looking-at fsharp-outdent-re))))
 
 
 (defun fsharp--indenting-comment-p ()
@@ -459,8 +458,7 @@ comment."
             (goto-char here)
             (beginning-of-line)
             (delete-horizontal-space)
-            (indent-to (- indent outdent))
-            )))))
+            (indent-to (- indent outdent)))))))
 
 
 ;; Electric deletion
@@ -582,8 +580,7 @@ This function is normally bound to `indent-line-function' so
                          (delete-horizontal-space)
                          (indent-to need)))
                    (if move-to-indentation-p (back-to-indentation)))
-          (insert-tab)))
-      )))
+          (insert-tab))))))
 
 
 ;; NOTE[gastove|2019-10-25] An interesting point: this function is *only* ever
@@ -686,8 +683,7 @@ above, but only when the previous line is not itself a continuation line."
       ;; statement, add some extra offset.
       (+ (current-column) (if (fsharp-statement-opens-block-p)
                               fsharp-continuation-offset 0)
-         1)
-      )))
+         1))))
 
 
 (defun fsharp--compute-indentation-relative-to-previous (honor-block-close-p)
@@ -720,11 +716,7 @@ lines (if any)"
                                   (back-to-indentation)
                                   (and (not (looking-at prefix-re))
                                        (or (looking-at "[^/]")
-                                           (not (zerop (current-column)))
-                                           ))
-                                  ))
-                           ))
-            )))
+                                           (not (zerop (current-column))))))))))))
       ;; if we landed inside a string, go to the beginning of that
       ;; string. this handles triple quoted, multi-line spanning
       ;; strings.
@@ -742,8 +734,7 @@ lines (if any)"
              fsharp-indent-offset
            (if (and honor-block-close-p (fsharp-statement-closes-block-p))
                (- fsharp-indent-offset)
-             0)))))
-  )
+             0))))))
 
 
 (defun fsharp-newline-and-indent ()
@@ -857,8 +848,7 @@ it's tried again going backward."
       (or noninteractive
           (message "%s value of fsharp-indent-offset set to %d"
                    (if global "Global" "Local")
-                   fsharp-indent-offset)))
-    ))
+                   fsharp-indent-offset)))))
 
 (defun fsharp-comment-indent-function ()
   "Fsharp version of `comment-indent-function'."
@@ -873,8 +863,7 @@ it's tried again going backward."
            (setq eol (match-beginning 0)))
       (goto-char eol)
       (skip-chars-backward " \t")
-      (max comment-column (+ (current-column) (if (bolp) 0 1)))
-      )))
+      (max comment-column (+ (current-column) (if (bolp) 0 1))))))
 
 (defun fsharp-narrow-to-defun (&optional class)
   "Make text outside current defun invisible.
@@ -1142,8 +1131,7 @@ To mark the current `def', see `\\[fsharp-mark-def-or-class]'."
         (start-of-stmt (goto-char (fsharp-point 'bos)))
         (start-re (cond ((eq class 'either) "^[ \t]*\\(type\\|let\\)\\>")
                         (class "^[ \t]*type\\>")
-                        (t "^[ \t]*let\\>")))
-        )
+                        (t "^[ \t]*let\\>"))))
     ;; searching backward
     (if (and (< 0 count)
              (or (/= start-of-stmt start-of-line)
@@ -1621,8 +1609,7 @@ moves to the end of the block (& does not set mark or display a msg)."
       (while (and
               (setq last-pos (point))   ; always true -- side effect
               (fsharp-goto-statement-below)
-              (> (current-indentation) initial-indent)
-              )))
+              (> (current-indentation) initial-indent))))
 
      ;; else plain code line; stop at next blank line, or stmt or
      ;; indenting comment line indented <
diff --git a/inf-fsharp-mode.el b/inf-fsharp-mode.el
index 15e821d..4a17abe 100644
--- a/inf-fsharp-mode.el
+++ b/inf-fsharp-mode.el
@@ -146,9 +146,7 @@ Input and output via buffer `*inferior-fsharp*'."
     (while
         (> count 0)
       (previous-multiframe-window)
-      (setq count (- count 1)))
-    )
-  )
+      (setq count (- count 1)))))
 
 (defun inferior-fsharp-eval-region (start end)
   "Send the current region to the inferior fsharp process."

From e3cbb2c34183739d8223c68d9beeb646b0cb2555 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Wed, 27 Oct 2021 17:31:00 +0200
Subject: [PATCH 069/147] Add workarounds for integration test

- Restart eglot server
- Sniff for current file-name whether parsing is complete.
---
 test/integration-tests.el | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 05a6391..9da6bd3 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -28,11 +28,13 @@
 (require 'eglot-fsharp)
 (require 'eglot-tests)
 
-(defun eglot-fsharp--sniff-diagnostics ()
+(defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
   (eglot--sniffing (:server-notifications s-notifs)
     (eglot--wait-for (s-notifs 20)
-	(&key _id method &allow-other-keys)
-      (string= method "textDocument/publishDiagnostics"))))
+                     (&key _id method params &allow-other-keys)
+                     (and
+                      (string= method "textDocument/publishDiagnostics")
+                      (string-suffix-p file-name-suffix (plist-get params :uri))))))
 
 (describe "F# LSP server"
   (it "Can be installed"
@@ -45,7 +47,7 @@
       (flymake-mode t)
       (flymake-start)
       (goto-char (point-min))
-      (eglot-fsharp--sniff-diagnostics)
+      (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
       (flymake-goto-next-error 1 '() t)
       (expect (face-at-point) :to-be 'flymake-error )))
   (it "is enabled on F# Files"
@@ -53,23 +55,24 @@
       (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
   (it "provides completion"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
-      (eglot-fsharp--sniff-diagnostics)
+      (eglot-fsharp--sniff-diagnostics "test/Test1/FileTwo.fs")
       (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))
   (it "completes function in other modules"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
       (search-forward "X.func")
       (delete-char -3)
-      ;; ERROR in fsautocomplet.exe?  Should block instead of "no type check results"
-      (eglot-fsharp--sniff-diagnostics)
+      (eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
       (completion-at-point)
       (expect (looking-back "X\\.func") :to-be t)))
   (it "finds definition in pervasives"
-    (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-      (eglot-fsharp--sniff-diagnostics)
-      (goto-char 253)
-      (expect (current-word) :to-equal "printfn") ;sanity check
-      (call-interactively #'xref-find-definitions)
-      (expect (file-name-nondirectory (buffer-file-name)) :to-equal "fslib-extra-pervasives.fs")))
+      (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+	(eglot-shutdown-all)		;FIXME: Why is a restart required
+	(eglot--tests-connect 10)
+	(search-forward "printfn")
+	(eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
+	(expect (current-word) :to-equal "printfn") ;sanity check
+	(call-interactively #'xref-find-definitions)
+	(expect (file-name-nondirectory (buffer-file-name)) :to-equal "fslib-extra-pervasives.fs")))
   (it "finds definitions in other files of Project"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
       (goto-char 150)

From b9e358adc8ef3c9b980419417ab819c831abe439 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@archlinux.org>
Date: Wed, 27 Oct 2021 17:31:00 +0200
Subject: [PATCH 070/147] Update TargetFramework for integration tests to
 net5.0

---
 test/Test1/Test1.fsproj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/Test1/Test1.fsproj b/test/Test1/Test1.fsproj
index 348b5cb..3d3561e 100644
--- a/test/Test1/Test1.fsproj
+++ b/test/Test1/Test1.fsproj
@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp2.1</TargetFramework>
+    <TargetFramework>net5.0</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>

From 18cb50b3425d54ae6ec984fc6a67721758dfa075 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 31 Oct 2021 17:06:26 +0100
Subject: [PATCH 071/147] Fix byte-compile warnings

---
 inf-fsharp-mode.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/inf-fsharp-mode.el b/inf-fsharp-mode.el
index 4a17abe..e14871c 100644
--- a/inf-fsharp-mode.el
+++ b/inf-fsharp-mode.el
@@ -28,7 +28,7 @@
 (require 'comint)
 (require 'fsharp-mode-util)
 
-(with-no-warnings (require 'cl))
+(require 'cl-lib)
 
 ;; User modifiable variables
 

From 12df37a4cab99a7719e4af9620a4223f4a517154 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 14 Nov 2021 13:56:07 +0100
Subject: [PATCH 072/147] Prefer dotnet core FSI

Fixes #280
---
 inf-fsharp-mode.el | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/inf-fsharp-mode.el b/inf-fsharp-mode.el
index e14871c..b3dc36e 100644
--- a/inf-fsharp-mode.el
+++ b/inf-fsharp-mode.el
@@ -38,10 +38,11 @@
   "*If true, display the inferior fsharp buffer when evaluating expressions.")
 
 (defvar inferior-fsharp-program
-  (if fsharp-ac-using-mono
-      "fsharpi --readline-"
-    (concat "\"" (fsharp-mode--executable-find "fsi.exe") "\" --fsi-server-input-codepage:65001"))
-  "*Program name for invoking an inferior fsharp from Emacs.")
+  (cond
+   ((executable-find "dotnet") "dotnet fsi --readline-")
+   (fsharp-ac-using-mono "fsharpi --readline-")
+   (t (concat "\"" (fsharp-mode--executable-find "fsi.exe") "\" --fsi-server-input-codepage:65001")))
+  "Inferior F# command.")
 
 ;; End of User modifiable variables
 

From 07208091d33f8cd0d311b6b98c8a50dde9f150f8 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Mon, 15 Nov 2021 15:15:26 +0100
Subject: [PATCH 073/147] Use fsautocomplete 0.48.2 for integration Tests

Testing fails when using fsautocomplete >= 0.49.
---
 test/integration-tests.el | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 9da6bd3..5e20f62 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -28,6 +28,8 @@
 (require 'eglot-fsharp)
 (require 'eglot-tests)
 
+(setq eglot-fsharp-server-version "0.48.2")
+
 (defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
   (eglot--sniffing (:server-notifications s-notifs)
     (eglot--wait-for (s-notifs 20)

From 24d5b4c3adf53b801615340e225fc33632ed8822 Mon Sep 17 00:00:00 2001
From: Shohei YOSHIDA <syohex@gmail.com>
Date: Wed, 29 Dec 2021 00:11:14 +0900
Subject: [PATCH 074/147] Use cl-lib function instead of cl.el's one

---
 inf-fsharp-mode.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/inf-fsharp-mode.el b/inf-fsharp-mode.el
index b3dc36e..7db9a09 100644
--- a/inf-fsharp-mode.el
+++ b/inf-fsharp-mode.el
@@ -79,7 +79,7 @@ be sent from another buffer in fsharp mode.
   ;; use compilation mode to parse errors, but RET and C-cC-c should still be from comint-mode
   (compilation-minor-mode)
   (make-local-variable 'minor-mode-map-alist)
-  (setq minor-mode-map-alist (assq-delete-all 'compilation-minor-mode (copy-seq minor-mode-map-alist))))
+  (setq minor-mode-map-alist (assq-delete-all 'compilation-minor-mode (cl-copy-seq minor-mode-map-alist))))
 
 (defconst inferior-fsharp-buffer-subname "inferior-fsharp")
 (defconst inferior-fsharp-buffer-name

From 5013666bddcade94531d5c5f788772d014e1035c Mon Sep 17 00:00:00 2001
From: Andrew McGuier <andrew@echogatetech.com>
Date: Wed, 26 Jan 2022 02:44:48 -0500
Subject: [PATCH 075/147] switching dotnet core over to using a tool install

---
 eglot-fsharp.el | 99 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 71 insertions(+), 28 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 3d8069f..542ff53 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -51,6 +51,9 @@
           (const :tag "Latest release" latest)
           (string :tag "Version string")))
 
+(defcustom eglot-fsharp-server-verbose nil
+  "If non-nil include debug output in the server logs.")
+
 (defcustom eglot-fsharp-server-runtime
   (if (executable-find "dotnet")
       'net-core
@@ -64,12 +67,16 @@
   "Return FsAutoComplete path."
   (file-truename (concat eglot-fsharp-server-install-dir
                          (if (eq eglot-fsharp-server-runtime 'net-core)
-                             "netcore/fsautocomplete.dll"
+                             "netcore/fsautocomplete"
                            "netframework/fsautocomplete.exe"))))
 
 ;; cache to prevent repetitive queries
 (defvar eglot-fsharp--github-version nil "Latest fsautocomplete.exe GitHub version string.")
 
+(defun eglot-fsharp--clean-version (version)
+  "Remove any spurious prefix from the version string VERSION."
+  (string-trim-left version "[Vv]"))
+
 (defun eglot-fsharp--github-version ()
   "Return latest fsautocomplete.exe GitHub version string."
   (or eglot-fsharp--github-version
@@ -95,21 +102,16 @@
   "Return t if the installation is not outdated."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (if (eq eglot-fsharp-server-version 'latest)
-        (equal (eglot-fsharp--github-version) (eglot-fsharp--installed-version))
-      (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
-
-(defun eglot-fsharp--maybe-install ()
-  "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
-  (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
-  (let* ((version (if (eq eglot-fsharp-server-version 'latest)
-                      (eglot-fsharp--github-version)
-                    eglot-fsharp-server-version))
-         (url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete%szip"
-                      version
-                      (if (eq eglot-fsharp-server-runtime 'net-core)
-                          ".netcore."
-                        ".")))
-         (exe (eglot-fsharp--path-to-server))
+	(equal (eglot-fsharp--clean-version (eglot-fsharp--github-version))
+	       (eglot-fsharp--clean-version (eglot-fsharp--installed-version)))
+      (equal (eglot-fsharp--clean-version eglot-fsharp-server-version)
+	     (eglot-fsharp--clean-version (eglot-fsharp--installed-version))))))
+
+(defun eglot-fsharp--install-w32 (version)
+  "Download and install the full framework version of F# compiler service at version VERSION in `eglot-fsharp-server-install-dir'."
+  (let* ((url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete.zip"
+                      version))
+	 (exe (eglot-fsharp--path-to-server))
          (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
          (gnutls-algorithm-priority
           (if (and (not gnutls-algorithm-priority)
@@ -117,8 +119,8 @@
                    (>= libgnutls-version 30603)
                    (version<= emacs-version "26.2"))
               "NORMAL:-VERS-TLS1.3"
-            gnutls-algorithm-priority)))
-    (unless (eglot-fsharp-current-version-p)
+            gnutls-algorithm-priority))))
+      (unless (eglot-fsharp-current-version-p)
       (url-copy-file url zip t)
       ;; FIXME: Windows (unzip preinstalled?)
       (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
@@ -129,21 +131,62 @@
 	    (if (file-directory-p file)
 		(chmod file #o755)
 	      (chmod file #o644)))))
-      (delete-file zip))))
+      (delete-file zip)))
+
+
+(defun eglot-fsharp--process-tool-action (response)
+  "Process the result of calling the dotnet tool installation returning RESPONSE code."
+  (if (eq response 1)
+      (let ((minibuffer-message-timeout 5)
+	    (msg (format "Error installing fsautocomplete see %s" (concat default-directory "error_output.txt")) ))
+	(minibuffer-message msg)
+	(error "Failed to install dotnet tool fsautocomplete"))))
+
+(defun eglot-fsharp--install-core (version)
+  "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."
+  (let ((vers (eglot-fsharp--clean-version version))
+	(default-directory (file-name-directory (eglot-fsharp--path-to-server))))
+    (unless (eglot-fsharp-current-version-p)
+      (if (file-exists-p (eglot-fsharp--path-to-server))
+	  (eglot-fsharp--process-tool-action	  (call-process "dotnet" nil '(nil
+									       "error_output.txt")
+								nil "tool" "uninstall"
+								"fsautocomplete" "--tool-path"
+								default-directory)))
+      (eglot-fsharp--process-tool-action (call-process "dotnet" nil '(nil "error_output.txt") nil
+						       "tool" "install" "fsautocomplete"
+						       "--tool-path" default-directory "--version"
+						       vers)))))
+
+(defun eglot-fsharp--maybe-install ()
+  "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
+  (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
+  (let* ((version (if (eq eglot-fsharp-server-version 'latest)
+                      (eglot-fsharp--github-version)
+                    eglot-fsharp-server-version)))
+  (if (eq eglot-fsharp-server-runtime 'net-core)
+      (eglot-fsharp--install-core version)
+    (eglot-fsharp--install-w32 version))))
 
  ;;;###autoload
-(defun eglot-fsharp (interactive)
+(defun eglot-fsharp
+    (interactive)
   "Return `eglot' contact when FsAutoComplete is installed.
 Ensure FsAutoComplete is installed (when called INTERACTIVE)."
-  (when interactive
-    (eglot-fsharp--maybe-install))
+  (when interactive (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
-    (cons 'eglot-fsautocomplete
-          `(,(cond
-              ((eq eglot-fsharp-server-runtime 'net-core) "dotnet")
-              ((eq window-system 'w32) "")
-              (t "mono"))
-            ,(eglot-fsharp--path-to-server) "--background-service-enabled"))))
+    (let ((cmd-list (cond ((eq eglot-fsharp-server-runtime 'net-core)
+			   `(,(eglot-fsharp--path-to-server)))
+			  ((eq window-system 'w32)
+			   `("" , (eglot-fsharp--path-to-server)))
+			  (t `("mono" ,(eglot-fsharp--path-to-server)))))
+	  (arg-list (if eglot-fsharp-server-verbose
+			`("--background-service-enabled" "-v")
+            	        `("--background-service-enabled")
+		      )))
+      (cons 'eglot-fsautocomplete (append cmd-list arg-list)))))
+
+
 
 
 (defclass eglot-fsautocomplete (eglot-lsp-server) ()

From 1b47760ceda47e7221870c5e5fbafe0ec8ca8baa Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Mon, 4 Apr 2022 20:26:57 +0200
Subject: [PATCH 076/147] Add 28.1 to build matrix

---
 .github/workflows/test.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9395e97..fc4ed61 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -15,6 +15,7 @@ jobs:
           - 26.3
           - 27.1
           - 27.2
+          - 28.1
           - snapshot
     steps:
     - uses: purcell/setup-emacs@master

From 85c14dd20733cecc91cded58f3b1c1afad8a8bbe Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Mon, 4 Apr 2022 21:00:23 +0200
Subject: [PATCH 077/147] Use "dotnet tool search" to determine latest
 fsautocomplete version

---
 eglot-fsharp.el | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 542ff53..b8ab947 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -77,18 +77,10 @@
   "Remove any spurious prefix from the version string VERSION."
   (string-trim-left version "[Vv]"))
 
-(defun eglot-fsharp--github-version ()
-  "Return latest fsautocomplete.exe GitHub version string."
-  (or eglot-fsharp--github-version
-      (with-temp-buffer
-        (condition-case err
-            (let ((json-object-type 'hash-table)
-                  (url-mime-accept-string "application/json"))
-              (url-insert-file-contents "https://github.com/fsharp/fsautocomplete/releases/latest")
-              (goto-char (point-min))
-              (setq eglot-fsharp--github-version (gethash "tag_name" (json-read))))
-          (file-error
-           (warn "fsautocomplete.exe update check:: %s" (error-message-string err)))))))
+(defun eglot-fsharp--latest-version ()
+  "Return latest fsautocomplete.exe version."
+  (seq-some (lambda (s) (and (string-match "^Latest Version: \\(.*\\)$" s) (match-string 1 s)))
+	    (process-lines "dotnet"  "tool" "search" "fsautocomplete" "--detail")))
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."

From 04cc1be0c3fb077688032d8a596e6ec8b2769dfc Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 5 Apr 2022 17:12:45 +0200
Subject: [PATCH 078/147] Use "dotnet tool list" to determine installed version

---
 eglot-fsharp.el | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index b8ab947..83cd3fa 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -84,11 +84,8 @@
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."
-  (when (file-exists-p (eglot-fsharp--path-to-server))
-    (let* ((cmd (append (cdr (eglot-fsharp nil)) '("--version")))
-           (version-line (concat (car (apply #'process-lines cmd)))))
-      (when (string-match "^FsAutoComplete \\([[:digit:].]+\\) " version-line)
-        (match-string 1 version-line)))))
+  (seq-some (lambda (s) (and (string-match "^fsautocomplete[[:space:]]+\\([0-9\.]*\\)[[:space:]]+" s) (match-string 1 s)))
+	    (process-lines "dotnet"  "tool" "list" "--tool-path" (file-name-directory (eglot-fsharp--path-to-server)))))
 
 (defun eglot-fsharp-current-version-p ()
   "Return t if the installation is not outdated."

From 2a8ec2b4ee69b96389adbe28902298ca4c8a8476 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 5 Apr 2022 09:57:13 +0200
Subject: [PATCH 079/147] Add macos to build matrix

---
 .github/workflows/test.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index fc4ed61..8b56c5b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,6 +11,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
+        os: [ubuntu-latest, macos-latest]
         emacs_version:
           - 26.3
           - 27.1

From 6a2034532f083ffd6ec3a07880c81b06c21b5280 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 5 Apr 2022 10:24:45 +0200
Subject: [PATCH 080/147] Cache eglot-fsharp--latest-version

---
 eglot-fsharp.el | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 83cd3fa..df5d1f6 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -71,7 +71,7 @@
                            "netframework/fsautocomplete.exe"))))
 
 ;; cache to prevent repetitive queries
-(defvar eglot-fsharp--github-version nil "Latest fsautocomplete.exe GitHub version string.")
+(defvar eglot-fsharp--latest-version nil "Latest fsautocomplete.exe version string.")
 
 (defun eglot-fsharp--clean-version (version)
   "Remove any spurious prefix from the version string VERSION."
@@ -79,8 +79,11 @@
 
 (defun eglot-fsharp--latest-version ()
   "Return latest fsautocomplete.exe version."
-  (seq-some (lambda (s) (and (string-match "^Latest Version: \\(.*\\)$" s) (match-string 1 s)))
-	    (process-lines "dotnet"  "tool" "search" "fsautocomplete" "--detail")))
+  (if eglot-fsharp--latest-version
+      eglot-fsharp--latest-version
+    (setq eglot-fsharp--latest-version
+	  (seq-some (lambda (s) (and (string-match "^Latest Version: \\(.*\\)$" s) (match-string 1 s)))
+		    (process-lines "dotnet"  "tool" "search" "fsautocomplete" "--detail")))))
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."
@@ -91,7 +94,7 @@
   "Return t if the installation is not outdated."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (if (eq eglot-fsharp-server-version 'latest)
-	(equal (eglot-fsharp--clean-version (eglot-fsharp--github-version))
+	(equal (eglot-fsharp--clean-version (eglot-fsharp--latest-version))
 	       (eglot-fsharp--clean-version (eglot-fsharp--installed-version)))
       (equal (eglot-fsharp--clean-version eglot-fsharp-server-version)
 	     (eglot-fsharp--clean-version (eglot-fsharp--installed-version))))))
@@ -151,7 +154,7 @@
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
   (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
   (let* ((version (if (eq eglot-fsharp-server-version 'latest)
-                      (eglot-fsharp--github-version)
+                      (eglot-fsharp--latest-version)
                     eglot-fsharp-server-version)))
   (if (eq eglot-fsharp-server-runtime 'net-core)
       (eglot-fsharp--install-core version)

From ccf007b43c2cbe4d49a6c09c3b4de4177cceeaf7 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 5 Apr 2022 10:39:00 +0200
Subject: [PATCH 081/147] Remove obsolete function

---
 eglot-fsharp.el | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index df5d1f6..4de557e 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -73,10 +73,6 @@
 ;; cache to prevent repetitive queries
 (defvar eglot-fsharp--latest-version nil "Latest fsautocomplete.exe version string.")
 
-(defun eglot-fsharp--clean-version (version)
-  "Remove any spurious prefix from the version string VERSION."
-  (string-trim-left version "[Vv]"))
-
 (defun eglot-fsharp--latest-version ()
   "Return latest fsautocomplete.exe version."
   (if eglot-fsharp--latest-version
@@ -94,10 +90,9 @@
   "Return t if the installation is not outdated."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (if (eq eglot-fsharp-server-version 'latest)
-	(equal (eglot-fsharp--clean-version (eglot-fsharp--latest-version))
-	       (eglot-fsharp--clean-version (eglot-fsharp--installed-version)))
-      (equal (eglot-fsharp--clean-version eglot-fsharp-server-version)
-	     (eglot-fsharp--clean-version (eglot-fsharp--installed-version))))))
+	(equal (eglot-fsharp--latest-version)
+	       (eglot-fsharp--installed-version))
+      (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
 
 (defun eglot-fsharp--install-w32 (version)
   "Download and install the full framework version of F# compiler service at version VERSION in `eglot-fsharp-server-install-dir'."
@@ -136,8 +131,7 @@
 
 (defun eglot-fsharp--install-core (version)
   "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."
-  (let ((vers (eglot-fsharp--clean-version version))
-	(default-directory (file-name-directory (eglot-fsharp--path-to-server))))
+  (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
     (unless (eglot-fsharp-current-version-p)
       (if (file-exists-p (eglot-fsharp--path-to-server))
 	  (eglot-fsharp--process-tool-action	  (call-process "dotnet" nil '(nil
@@ -148,7 +142,7 @@
       (eglot-fsharp--process-tool-action (call-process "dotnet" nil '(nil "error_output.txt") nil
 						       "tool" "install" "fsautocomplete"
 						       "--tool-path" default-directory "--version"
-						       vers)))))
+						       version)))))
 
 (defun eglot-fsharp--maybe-install ()
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
@@ -156,9 +150,9 @@
   (let* ((version (if (eq eglot-fsharp-server-version 'latest)
                       (eglot-fsharp--latest-version)
                     eglot-fsharp-server-version)))
-  (if (eq eglot-fsharp-server-runtime 'net-core)
-      (eglot-fsharp--install-core version)
-    (eglot-fsharp--install-w32 version))))
+    (if (eq eglot-fsharp-server-runtime 'net-core)
+	(eglot-fsharp--install-core version)
+      (eglot-fsharp--install-w32 version))))
 
  ;;;###autoload
 (defun eglot-fsharp

From 5d584b18b320258cf061be4433c4ec7be5415ebe Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 5 Apr 2022 10:51:32 +0200
Subject: [PATCH 082/147] Use latest fsautocomplete version in tests

---
 test/integration-tests.el | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 5e20f62..ec3ed53 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -28,8 +28,6 @@
 (require 'eglot-fsharp)
 (require 'eglot-tests)
 
-(setq eglot-fsharp-server-version "0.48.2")
-
 (defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
   (eglot--sniffing (:server-notifications s-notifs)
     (eglot--wait-for (s-notifs 20)
@@ -41,7 +39,7 @@
 (describe "F# LSP server"
   (it "Can be installed"
     (eglot-fsharp--maybe-install)
-    (expect (file-exists-p  (eglot-fsharp--path-to-server)) :to-be t))
+    (expect (eglot-fsharp--installed-version) :to-equal (eglot-fsharp--latest-version)))
   (it "shows flymake errors"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Error.fs")
       (eglot--tests-connect 10)

From e2de4b0c38fefcd1150956a3053bba132db4209a Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 5 Apr 2022 12:00:01 +0200
Subject: [PATCH 083/147] Add Pervasive testfile

Prevents side-effects with other integration tests
---
 test/Test1/Pervasive.fs   | 3 +++
 test/Test1/Test1.fsproj   | 1 +
 test/integration-tests.el | 1 -
 3 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 test/Test1/Pervasive.fs

diff --git a/test/Test1/Pervasive.fs b/test/Test1/Pervasive.fs
new file mode 100644
index 0000000..4fb011c
--- /dev/null
+++ b/test/Test1/Pervasive.fs
@@ -0,0 +1,3 @@
+let printtest args =
+    printfn "Hello %d" 10
+    0
diff --git a/test/Test1/Test1.fsproj b/test/Test1/Test1.fsproj
index 3d3561e..15ef69f 100644
--- a/test/Test1/Test1.fsproj
+++ b/test/Test1/Test1.fsproj
@@ -9,6 +9,7 @@
     <Compile Include="Error.fs" />
     <Compile Include="FileTwo.fs" />
     <Compile Include="Program.fs" />
+    <Compile Include="Pervasive.fs" />
   </ItemGroup>
 
 </Project>
diff --git a/test/integration-tests.el b/test/integration-tests.el
index ec3ed53..84c1b84 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -66,7 +66,6 @@
       (expect (looking-back "X\\.func") :to-be t)))
   (it "finds definition in pervasives"
       (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-	(eglot-shutdown-all)		;FIXME: Why is a restart required
 	(eglot--tests-connect 10)
 	(search-forward "printfn")
 	(eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")

From 17866a01a24edf6728847a792a29e64e453fa3b8 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Thu, 7 Apr 2022 13:52:26 +0200
Subject: [PATCH 084/147] New test: "Can be invoked"

---
 test/integration-tests.el | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 84c1b84..2ce5884 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -40,6 +40,10 @@
   (it "Can be installed"
     (eglot-fsharp--maybe-install)
     (expect (eglot-fsharp--installed-version) :to-equal (eglot-fsharp--latest-version)))
+  (it "Can be invoked"
+      ;; FIXME: Should use dotnet tool run
+      (expect (car (process-lines (eglot-fsharp--path-to-server) "--version"))
+	      :to-match (rx line-start "FsAutoComplete" (1+ space) (eval (eglot-fsharp--installed-version)))))
   (it "shows flymake errors"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Error.fs")
       (eglot--tests-connect 10)

From 737c9347f3c7ccf2d56c345b2841c6c26e33a244 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Thu, 7 Apr 2022 14:31:51 +0200
Subject: [PATCH 085/147] setup-dotnet: Use explicit dotnet version

---
 .github/workflows/test.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 8b56c5b..006ca3d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -12,6 +12,7 @@ jobs:
       fail-fast: false
       matrix:
         os: [ubuntu-latest, macos-latest]
+        dotnet: [6.0.200]
         emacs_version:
           - 26.3
           - 27.1
@@ -23,6 +24,8 @@ jobs:
       with:
         version: ${{ matrix.emacs_version }}
     - uses: actions/setup-dotnet@v1
+      with:
+        dotnet-version: ${{ matrix.dotnet }}
     - uses: actions/checkout@v2
     - uses: conao3/setup-cask@master
     - name: Show dotnet sdks

From 2ef572ff52d5b245ca26505c3e12b7d356b23ffc Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Thu, 7 Apr 2022 14:56:49 +0200
Subject: [PATCH 086/147] Remove support for Emacs 26.3

---
 .github/workflows/test.yml | 1 -
 eglot-fsharp.el            | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 006ca3d..c04d1e6 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -14,7 +14,6 @@ jobs:
         os: [ubuntu-latest, macos-latest]
         dotnet: [6.0.200]
         emacs_version:
-          - 26.3
           - 27.1
           - 27.2
           - 28.1
diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 4de557e..e6ff8c9 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2021  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@archlinux.org>
-;; Package-Requires: ((emacs "26.3") (eglot "1.4") (fsharp-mode "1.10") (jsonrpc "1.0.14"))
+;; Package-Requires: ((emacs "27.1") (eglot "1.4") (fsharp-mode "1.10") (jsonrpc "1.0.14"))
 ;; Version: 1.10
 ;; Keywords: languages
 ;; URL: https://github.com/fsharp/emacs-fsharp-mode

From e52e71a7144f973d8d48cc5afc57f5a2f1cfcc99 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Thu, 7 Apr 2022 15:43:25 +0200
Subject: [PATCH 087/147] Update Docs

---
 README.org | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.org b/README.org
index 93a1b09..4983d8b 100644
--- a/README.org
+++ b/README.org
@@ -19,7 +19,7 @@ The current version of =fsharp-mode= installs =fsautocomplete.exe=
 automatically via =eglot-fsharp.el= (part of this mono repo, [[https://melpa.org/#/eglot-fsharp][eglot-fsharp
 on melpa]]) or [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]] (untested).
 
-=fsharp-mode= is tested with Emacs 26.1+ and NET Core 2.1 (LTS)
+=fsharp-mode= is tested with Emacs 27.1+ and NET Core 6 (LTS)
 
 ** Installation
 

From ee2440c93b718481ba2b8e025b70654900487fd8 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 8 Apr 2022 15:15:17 +0200
Subject: [PATCH 088/147] Remove unused dependency

---
 fsharp-mode.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index c8e0153..54e6697 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -5,9 +5,9 @@
 ;; Author: 1993-1997 Xavier Leroy, Jacques Garrigue and Ian T Zimmerman
 ;;         2010-2011 Laurent Le Brun <laurent@le-brun.eu>
 ;;         2012-2014 Robin Neatherway <robin.neatherway@gmail.com>
-;;         2017-2021 Jürgen Hötzel
+;;         2017-2022 Jürgen Hötzel
 ;; Maintainer: Jürgen Hötzel
-;; Package-Requires: ((emacs "25")  (s "1.3.1"))
+;; Package-Requires: ((emacs "25"))
 ;; Keywords: languages
 ;; Version: 1.11-snapshot
 

From 73fc04979707b7ea42c1b756579c94b735790eb2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 9 Apr 2022 20:06:46 +0200
Subject: [PATCH 089/147] Use C-locale when interacting with "dotnet search"

Prevent parsing failures when using non-C-locales
---
 eglot-fsharp.el | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index e6ff8c9..9890528 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -75,11 +75,12 @@
 
 (defun eglot-fsharp--latest-version ()
   "Return latest fsautocomplete.exe version."
-  (if eglot-fsharp--latest-version
-      eglot-fsharp--latest-version
-    (setq eglot-fsharp--latest-version
-	  (seq-some (lambda (s) (and (string-match "^Latest Version: \\(.*\\)$" s) (match-string 1 s)))
-		    (process-lines "dotnet"  "tool" "search" "fsautocomplete" "--detail")))))
+  (let ((process-environment (cons  "LANG=C" process-environment))) ;FIXME: Does this work in Windows
+    (if eglot-fsharp--latest-version
+        eglot-fsharp--latest-version
+      (setq eglot-fsharp--latest-version
+            (seq-some (lambda (s) (and (string-match "^Latest Version: \\(.*\\)$" s) (match-string 1 s)))
+                      (process-lines "dotnet"  "tool" "search" "fsautocomplete" "--detail"))))))
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."

From e440709635b939f47e4e4bb9e8ba3460e6d09f89 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sat, 23 Apr 2022 14:49:23 +0200
Subject: [PATCH 090/147] `fsharp-mode-project-root`: Don't traverse filesystem
 twice

Use improved regex.
---
 fsharp-mode.el | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index 54e6697..8d25a25 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -347,15 +347,7 @@ whole string."
 (defun fsharp-mode/find-sln-or-fsproj (dir-or-file)
   "Search for a solution or F# project file in any enclosing
 folders relative to DIR-OR-FILE."
-  (or (fsharp-mode/find-sln dir-or-file)
-      (fsharp-mode/find-fsproj dir-or-file)))
-
-(defun fsharp-mode/find-sln (dir-or-file)
-  (fsharp-mode-search-upwards (rx (0+ nonl) ".sln" eol)
-                              (file-name-directory dir-or-file)))
-
-(defun fsharp-mode/find-fsproj (dir-or-file)
-  (fsharp-mode-search-upwards (rx (0+ nonl) ".fsproj" eol)
+  (fsharp-mode-search-upwards (rx (0+ nonl) (or ".fsproj" ".sln") eol)
                               (file-name-directory dir-or-file)))
 
 (defun fsharp-mode-search-upwards (regex dir)

From e079429ac3cd94fa01b943b970f72ecb4d5bf955 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sat, 23 Apr 2022 15:10:58 +0200
Subject: [PATCH 091/147] Fix CI: New versions of fsautocomplete.exe changed
 version output

---
 test/integration-tests.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 2ce5884..666707b 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -43,7 +43,7 @@
   (it "Can be invoked"
       ;; FIXME: Should use dotnet tool run
       (expect (car (process-lines (eglot-fsharp--path-to-server) "--version"))
-	      :to-match (rx line-start "FsAutoComplete" (1+ space) (eval (eglot-fsharp--installed-version)))))
+	      :to-match (rx line-start (? "FsAutoComplete" (1+ space)) (eval (eglot-fsharp--installed-version)))))
   (it "shows flymake errors"
     (with-current-buffer (eglot--find-file-noselect "test/Test1/Error.fs")
       (eglot--tests-connect 10)

From 82ab2164bb407511ed366aac54bf37a310fc052a Mon Sep 17 00:00:00 2001
From: Marcos Magueta <mmagueta@MacMini.local>
Date: Thu, 28 Apr 2022 19:53:52 -0300
Subject: [PATCH 092/147] fix: adds match! as a valid keyword

---
 fsharp-mode-font.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fsharp-mode-font.el b/fsharp-mode-font.el
index 648e90d..c9c4770 100644
--- a/fsharp-mode-font.el
+++ b/fsharp-mode-font.el
@@ -242,7 +242,7 @@ with initial value INITVALUE and optional DOCSTRING."
     "exception" "extern" "false" "finally" "for" "fun"
     "function" "global" "if" "in" "inherit" "inline"
     "interface" "internal" "lazy" "let" "let!"
-    "match" "member" "module" "mutable" "namespace"
+    "match" "match!" "member" "module" "mutable" "namespace"
     "new" "not" "null" "of" "open" "or" "override"
     "private" "public" "rec" "return" "return!"
     "select" "static" "struct" "then" "to" "true"

From bf6b76981c7c2e362c75a818512ef78fee41bb96 Mon Sep 17 00:00:00 2001
From: Florian Biermann <flbm@simcorp.com>
Date: Mon, 30 May 2022 11:12:18 +0100
Subject: [PATCH 093/147] Use fsautocomplete.exe on Windows

---
 eglot-fsharp.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 9890528..dd72af2 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -67,7 +67,7 @@
   "Return FsAutoComplete path."
   (file-truename (concat eglot-fsharp-server-install-dir
                          (if (eq eglot-fsharp-server-runtime 'net-core)
-                             "netcore/fsautocomplete"
+                             (concat "netcore/fsautocomplete" (if (eq system-type 'windows-nt) ".exe" ""))
                            "netframework/fsautocomplete.exe"))))
 
 ;; cache to prevent repetitive queries

From e1fd9f222b6b0d78237417a996053dd30d2e1406 Mon Sep 17 00:00:00 2001
From: Marcos Magueta <maguetamarcos@gmail.com>
Date: Tue, 31 May 2022 22:57:25 -0300
Subject: [PATCH 094/147] add: applicative keyword on highlight

---
 fsharp-mode-font.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fsharp-mode-font.el b/fsharp-mode-font.el
index c9c4770..698f65e 100644
--- a/fsharp-mode-font.el
+++ b/fsharp-mode-font.el
@@ -236,7 +236,7 @@ with initial value INITVALUE and optional DOCSTRING."
 
 ;; F# keywords (3.4)
 (def-fsharp-compiled-var fsharp-ui-fsharp-threefour-keywords
-  '("abstract" "and" "as" "assert" "base" "begin"
+  '("abstract" "and" "and!" "as" "assert" "base" "begin"
     "class" "default" "delegate" "do" "do!" "done"
     "downcast" "downto" "elif" "else" "end"
     "exception" "extern" "false" "finally" "for" "fun"

From 8881451d9675a17d530f6516f892dae803d84b9f Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Wed, 1 Jun 2022 19:38:41 +0200
Subject: [PATCH 095/147] Update Keywords to F# 5.0

---
 fsharp-mode-font.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fsharp-mode-font.el b/fsharp-mode-font.el
index 698f65e..945d148 100644
--- a/fsharp-mode-font.el
+++ b/fsharp-mode-font.el
@@ -234,7 +234,7 @@ with initial value INITVALUE and optional DOCSTRING."
 (def-fsharp-compiled-var fsharp-ui-identifier-replacements
   '("__SOURCE_DIRECTORY__" "__SOURCE_FILE__" "__LINE__"))
 
-;; F# keywords (3.4)
+;; F# keywords (5.0)
 (def-fsharp-compiled-var fsharp-ui-fsharp-threefour-keywords
   '("abstract" "and" "and!" "as" "assert" "base" "begin"
     "class" "default" "delegate" "do" "do!" "done"

From a2903e6bc28602f3af1b836b61f41bec64bd85b0 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Wed, 1 Jun 2022 21:03:51 +0200
Subject: [PATCH 096/147] Generalize version string match

LANG=C workaround doesn't work on Windows
---
 eglot-fsharp.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index dd72af2..3c4ace8 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -75,11 +75,11 @@
 
 (defun eglot-fsharp--latest-version ()
   "Return latest fsautocomplete.exe version."
-  (let ((process-environment (cons  "LANG=C" process-environment))) ;FIXME: Does this work in Windows
+  (let ((process-environment (cons  "LANG=C" process-environment))) ;FIXME: Doesn't work in Windows
     (if eglot-fsharp--latest-version
         eglot-fsharp--latest-version
       (setq eglot-fsharp--latest-version
-            (seq-some (lambda (s) (and (string-match "^Latest Version: \\(.*\\)$" s) (match-string 1 s)))
+            (seq-some (lambda (s) (and (string-match "^[[:alnum:]]* Version: \\(.*\\)$" s) (match-string 1 s)))
                       (process-lines "dotnet"  "tool" "search" "fsautocomplete" "--detail"))))))
 
 (defun eglot-fsharp--installed-version ()

From 7be32c00e8d8aee3ed40a756f974800b4e20ab62 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sat, 4 Jun 2022 14:26:12 +0200
Subject: [PATCH 097/147] Also install specific version in integration tests

Refs #297
---
 eglot-fsharp.el           | 16 ++++++++--------
 test/integration-tests.el |  3 +++
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 3c4ace8..eb6a0d9 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -87,10 +87,10 @@
   (seq-some (lambda (s) (and (string-match "^fsautocomplete[[:space:]]+\\([0-9\.]*\\)[[:space:]]+" s) (match-string 1 s)))
 	    (process-lines "dotnet"  "tool" "list" "--tool-path" (file-name-directory (eglot-fsharp--path-to-server)))))
 
-(defun eglot-fsharp-current-version-p ()
+(defun eglot-fsharp-current-version-p (version)
   "Return t if the installation is not outdated."
   (when (file-exists-p (eglot-fsharp--path-to-server))
-    (if (eq eglot-fsharp-server-version 'latest)
+    (if (eq version 'latest)
 	(equal (eglot-fsharp--latest-version)
 	       (eglot-fsharp--installed-version))
       (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
@@ -108,7 +108,7 @@
                    (version<= emacs-version "26.2"))
               "NORMAL:-VERS-TLS1.3"
             gnutls-algorithm-priority))))
-      (unless (eglot-fsharp-current-version-p)
+      (unless (eglot-fsharp-current-version-p version)
       (url-copy-file url zip t)
       ;; FIXME: Windows (unzip preinstalled?)
       (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
@@ -133,7 +133,7 @@
 (defun eglot-fsharp--install-core (version)
   "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."
   (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
-    (unless (eglot-fsharp-current-version-p)
+    (unless (eglot-fsharp-current-version-p version)
       (if (file-exists-p (eglot-fsharp--path-to-server))
 	  (eglot-fsharp--process-tool-action	  (call-process "dotnet" nil '(nil
 									       "error_output.txt")
@@ -145,12 +145,12 @@
 						       "--tool-path" default-directory "--version"
 						       version)))))
 
-(defun eglot-fsharp--maybe-install ()
+(defun eglot-fsharp--maybe-install (&optional version)
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
   (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
-  (let* ((version (if (eq eglot-fsharp-server-version 'latest)
-                      (eglot-fsharp--latest-version)
-                    eglot-fsharp-server-version)))
+  (let* ((version (or version (if (eq eglot-fsharp-server-version 'latest)
+				  (eglot-fsharp--latest-version)
+				eglot-fsharp-server-version))))
     (if (eq eglot-fsharp-server-runtime 'net-core)
 	(eglot-fsharp--install-core version)
       (eglot-fsharp--install-w32 version))))
diff --git a/test/integration-tests.el b/test/integration-tests.el
index 666707b..1646876 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -37,6 +37,9 @@
                       (string-suffix-p file-name-suffix (plist-get params :uri))))))
 
 (describe "F# LSP server"
+  (it "can be installed @version 0.52.0"
+    (eglot-fsharp--maybe-install "0.52.0")
+    (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
   (it "Can be installed"
     (eglot-fsharp--maybe-install)
     (expect (eglot-fsharp--installed-version) :to-equal (eglot-fsharp--latest-version)))

From c4bdaca0a45e6678737b050ea740d7e0df179888 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 5 Jun 2022 15:18:06 +0200
Subject: [PATCH 098/147] Enforce code style via .dir-locals.el

---
 .dir-locals.el | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 .dir-locals.el

diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..f4b5d5e
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,5 @@
+;;; Directory Local Variables
+;;; For more information see (info "(emacs) Directory Variables")
+
+((emacs-lisp-mode . ((indent-tabs-mode . nil)
+		     (fill-column . 120))))

From e1a9aa2916410f9d7050b12728419f38fb928774 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 5 Jun 2022 15:22:48 +0200
Subject: [PATCH 099/147] .gitignore: Ignore Emacs backup files

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index f6d7269..954af47 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 *.elc
 bin
 tmp
+*~
 
 # Useful for doing releases
 emacs-fsharp-mode-bin/

From 5ff264a25c75fb9fd1c42295fda93dddc76b4624 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 5 Jun 2022 15:23:23 +0200
Subject: [PATCH 100/147] Reindent all files using .dir-locals.el setup

---
 eglot-fsharp.el                     |  26 +-
 fsharp-mode-font.el                 | 214 ++++++++--------
 test/fsharp-mode-font-tests.el      |  28 +--
 test/fsharp-mode-structure-tests.el | 370 ++++++++++++++--------------
 test/integration-tests.el           | 110 +++++----
 5 files changed, 375 insertions(+), 373 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index eb6a0d9..30ab7e1 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -108,18 +108,18 @@
                    (version<= emacs-version "26.2"))
               "NORMAL:-VERS-TLS1.3"
             gnutls-algorithm-priority))))
-      (unless (eglot-fsharp-current-version-p version)
-      (url-copy-file url zip t)
-      ;; FIXME: Windows (unzip preinstalled?)
-      (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
-        (unless (zerop (call-process "unzip" nil nil nil "-o" zip))
-          (error "Failed to unzip %s" zip))
-	(unless (eq system-type 'windows-nt)
-	  (dolist  (file (directory-files-recursively (file-name-directory (eglot-fsharp--path-to-server)) "." t))
-	    (if (file-directory-p file)
-		(chmod file #o755)
-	      (chmod file #o644)))))
-      (delete-file zip)))
+  (unless (eglot-fsharp-current-version-p version)
+    (url-copy-file url zip t)
+    ;; FIXME: Windows (unzip preinstalled?)
+    (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
+      (unless (zerop (call-process "unzip" nil nil nil "-o" zip))
+        (error "Failed to unzip %s" zip))
+      (unless (eq system-type 'windows-nt)
+	(dolist  (file (directory-files-recursively (file-name-directory (eglot-fsharp--path-to-server)) "." t))
+	  (if (file-directory-p file)
+	      (chmod file #o755)
+	    (chmod file #o644)))))
+    (delete-file zip)))
 
 
 (defun eglot-fsharp--process-tool-action (response)
@@ -169,7 +169,7 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
 			  (t `("mono" ,(eglot-fsharp--path-to-server)))))
 	  (arg-list (if eglot-fsharp-server-verbose
 			`("--background-service-enabled" "-v")
-            	        `("--background-service-enabled")
+            	      `("--background-service-enabled")
 		      )))
       (cons 'eglot-fsautocomplete (append cmd-list arg-list)))))
 
diff --git a/fsharp-mode-font.el b/fsharp-mode-font.el
index 945d148..0af65b2 100644
--- a/fsharp-mode-font.el
+++ b/fsharp-mode-font.el
@@ -61,97 +61,97 @@ with initial value INITVALUE and optional DOCSTRING."
      (defvar ,sym ,init ,docstring)))
 
 (def-fsharp-compiled-var fsharp-shebang-regexp
-  "\\(^#!.*?\\)\\([A-Za-z0-9_-]+\\)$"
-  "Capture the #! and path of a shebag in one group and the
+                         "\\(^#!.*?\\)\\([A-Za-z0-9_-]+\\)$"
+                         "Capture the #! and path of a shebag in one group and the
   executable in another.")
 
 (def-fsharp-compiled-var fsharp-access-control-regexp
-  "private\\s-+\\|internal\\s-+\\|public\\s-+"
-  "Match `private', `internal', or `public', followed by a space,
+                         "private\\s-+\\|internal\\s-+\\|public\\s-+"
+                         "Match `private', `internal', or `public', followed by a space,
   with no capture.")
 
 (def-fsharp-compiled-var fsharp-access-control-regexp-noncapturing
-  (format "\\(?:%s\\)" fsharp-access-control-regexp)
-  "Same as `fsharp-access-control-regexp', but captures")
+                         (format "\\(?:%s\\)" fsharp-access-control-regexp)
+                         "Same as `fsharp-access-control-regexp', but captures")
 
 (def-fsharp-compiled-var fsharp-inline-rec-regexp
-  "inline\\s-+\\|rec\\s-+"
-  "Match `inline' or `rec', followed by a space.")
+                         "inline\\s-+\\|rec\\s-+"
+                         "Match `inline' or `rec', followed by a space.")
 
 (def-fsharp-compiled-var fsharp-inline-rec-regexp-noncapturing
-  (format "\\(?:%s\\)" fsharp-inline-rec-regexp)
-  "Match `inline' or `rec', followed by a space, with no capture.")
+                         (format "\\(?:%s\\)" fsharp-inline-rec-regexp)
+                         "Match `inline' or `rec', followed by a space, with no capture.")
 
 (def-fsharp-compiled-var fsharp-valid-identifier-regexp
-  "[A-Za-z0-9_']+"
-  "Match a normal, valid F# identifier -- alphanumeric characters
+                         "[A-Za-z0-9_']+"
+                         "Match a normal, valid F# identifier -- alphanumeric characters
   plus ' and underbar. Does not capture")
 
 (def-fsharp-compiled-var fsharp-function-def-regexp
-  (concat "\\<\\(?:let\\|and\\|with\\)\\s-+"
-          fsharp-inline-rec-regexp-noncapturing "?"
-          fsharp-access-control-regexp-noncapturing "*"
-          (format "\\(%s\\)" fsharp-valid-identifier-regexp)
-          "\\(?:\\s-+[A-Za-z_]\\|\\s-*(\\)" ;; matches function arguments or open-paren; unclear why 0-9 not in class
-          ))
+                         (concat "\\<\\(?:let\\|and\\|with\\)\\s-+"
+                                 fsharp-inline-rec-regexp-noncapturing "?"
+                                 fsharp-access-control-regexp-noncapturing "*"
+                                 (format "\\(%s\\)" fsharp-valid-identifier-regexp)
+                                 "\\(?:\\s-+[A-Za-z_]\\|\\s-*(\\)" ;; matches function arguments or open-paren; unclear why 0-9 not in class
+                                 ))
 
 (def-fsharp-compiled-var fsharp-pattern-function-regexp
-  (concat "\\<\\(?:let\\|and\\)\\s-+"
-          fsharp-inline-rec-regexp-noncapturing "?"
-          fsharp-access-control-regexp-noncapturing "*"
-          (format "\\(%s\\)" fsharp-valid-identifier-regexp)
-          "\\s-*=\\s-*function")
-  "Matches an implicit matcher, eg let foo m = function | \"cat\" -> etc.")
+                         (concat "\\<\\(?:let\\|and\\)\\s-+"
+                                 fsharp-inline-rec-regexp-noncapturing "?"
+                                 fsharp-access-control-regexp-noncapturing "*"
+                                 (format "\\(%s\\)" fsharp-valid-identifier-regexp)
+                                 "\\s-*=\\s-*function")
+                         "Matches an implicit matcher, eg let foo m = function | \"cat\" -> etc.")
 
 ;; Note that this regexp is used for iMenu. To font-lock active patterns, we
 ;; need to use an anchored match in fsharp-font-lock-keywords.
 (def-fsharp-compiled-var fsharp-active-pattern-regexp
-  (concat "\\<\\(?:let\\|and\\)\\s-+"
-          fsharp-inline-rec-regexp-noncapturing "?"
-          fsharp-access-control-regexp-noncapturing "*"
-          "(\\(|[A-Za-z0-9_'|]+|\\))\\(?:\\s-+[A-Za-z_]\\|\\s-*(\\)"))
+                         (concat "\\<\\(?:let\\|and\\)\\s-+"
+                                 fsharp-inline-rec-regexp-noncapturing "?"
+                                 fsharp-access-control-regexp-noncapturing "*"
+                                 "(\\(|[A-Za-z0-9_'|]+|\\))\\(?:\\s-+[A-Za-z_]\\|\\s-*(\\)"))
 
 (def-fsharp-compiled-var fsharp-member-access-regexp
-  "\\<\\(?:override\\|member\\|abstract\\)\\s-+"
-  "Matches members declarations and modifiers on classes.")
+                         "\\<\\(?:override\\|member\\|abstract\\)\\s-+"
+                         "Matches members declarations and modifiers on classes.")
 
 (def-fsharp-compiled-var fsharp-member-function-regexp
-  (concat fsharp-member-access-regexp
-          fsharp-inline-rec-regexp-noncapturing "?"
-          fsharp-access-control-regexp-noncapturing "*"
-          "\\(?:" fsharp-valid-identifier-regexp "\\.\\)?"
-          "\\(" fsharp-valid-identifier-regexp "\\)")
-  "Captures the final identifier in a member function declaration.")
+                         (concat fsharp-member-access-regexp
+                                 fsharp-inline-rec-regexp-noncapturing "?"
+                                 fsharp-access-control-regexp-noncapturing "*"
+                                 "\\(?:" fsharp-valid-identifier-regexp "\\.\\)?"
+                                 "\\(" fsharp-valid-identifier-regexp "\\)")
+                         "Captures the final identifier in a member function declaration.")
 
 (def-fsharp-compiled-var fsharp-overload-operator-regexp
-  (concat fsharp-member-access-regexp
-          fsharp-inline-rec-regexp-noncapturing "?"
-          fsharp-access-control-regexp-noncapturing "*"
-          "\\(([!%&*+-./<=>?@^|~]+)\\)")
-  "Match operators when overloaded by a type/class.")
+                         (concat fsharp-member-access-regexp
+                                 fsharp-inline-rec-regexp-noncapturing "?"
+                                 fsharp-access-control-regexp-noncapturing "*"
+                                 "\\(([!%&*+-./<=>?@^|~]+)\\)")
+                         "Match operators when overloaded by a type/class.")
 
 (def-fsharp-compiled-var fsharp-constructor-regexp
-  (concat "^\\s-*"
-          fsharp-access-control-regexp-noncapturing "*"
-          "\\<\\(new\\) *(.*)[^=]*=")
-  "Matches the `new' keyword in a constructor")
+                         (concat "^\\s-*"
+                                 fsharp-access-control-regexp-noncapturing "*"
+                                 "\\<\\(new\\) *(.*)[^=]*=")
+                         "Matches the `new' keyword in a constructor")
 
 (def-fsharp-compiled-var fsharp-type-def-regexp
-  (concat "^\\s-*\\<\\(?:type\\|inherit\\)\\s-+"
-          fsharp-access-control-regexp-noncapturing "*" ;; match access control 0 or more times
-          "\\([A-Za-z0-9_'.]+\\)"))
+                         (concat "^\\s-*\\<\\(?:type\\|inherit\\)\\s-+"
+                                 fsharp-access-control-regexp-noncapturing "*" ;; match access control 0 or more times
+                                 "\\([A-Za-z0-9_'.]+\\)"))
 
 (def-fsharp-compiled-var fsharp-var-or-arg-regexp
-  "\\_<\\([A-Za-z_][A-Za-z0-9_']*\\)\\_>")
+                         "\\_<\\([A-Za-z_][A-Za-z0-9_']*\\)\\_>")
 
 (def-fsharp-compiled-var fsharp-explicit-field-regexp
-  (concat "^\\s-*\\(?:val\\|abstract\\)\\s-*\\(?:mutable\\s-+\\)?"
-          fsharp-access-control-regexp-noncapturing "*" ;; match access control 0 or more times
-          "\\([A-Za-z_][A-Za-z0-9_']*\\)\\s-*:\\s-*\\([A-Za-z_][A-Za-z0-9_'<> \t]*\\)"))
+                         (concat "^\\s-*\\(?:val\\|abstract\\)\\s-*\\(?:mutable\\s-+\\)?"
+                                 fsharp-access-control-regexp-noncapturing "*" ;; match access control 0 or more times
+                                 "\\([A-Za-z_][A-Za-z0-9_']*\\)\\s-*:\\s-*\\([A-Za-z_][A-Za-z0-9_'<> \t]*\\)"))
 
 (def-fsharp-compiled-var fsharp-attributes-regexp
-  "\\(\\[<[A-Za-z0-9_]+[( ]?\\)\\(\".*\"\\)?\\()?>\\]\\)"
-  "Match attributes like [<EntryPoint>]; separately groups contained strings in attributes like [<Attribute(\"property\")>]")
+                         "\\(\\[<[A-Za-z0-9_]+[( ]?\\)\\(\".*\"\\)?\\()?>\\]\\)"
+                         "Match attributes like [<EntryPoint>]; separately groups contained strings in attributes like [<Attribute(\"property\")>]")
 
 ;; F# makes extensive use of operators, many of which have some kind of
 ;; structural significance.
@@ -164,27 +164,27 @@ with initial value INITVALUE and optional DOCSTRING."
 ;; |                         -- match / type expressions
 
 (def-fsharp-compiled-var fsharp-operator-quote-regexp
-  "\\(<@\\{1,2\\}\\)\\(?:.*\\)\\(@\\{1,2\\}>\\)"
-  "Font lock <@/<@@ and @>/@@> operators.")
+                         "\\(<@\\{1,2\\}\\)\\(?:.*\\)\\(@\\{1,2\\}>\\)"
+                         "Font lock <@/<@@ and @>/@@> operators.")
 
 (def-fsharp-compiled-var fsharp-operator-pipe-regexp
-  "<|\\{1,3\\}\\||\\{1,3\\}>"
-  "Match the full range of pipe operators -- |>, ||>, |||>, etc.")
+                         "<|\\{1,3\\}\\||\\{1,3\\}>"
+                         "Match the full range of pipe operators -- |>, ||>, |||>, etc.")
 
 (def-fsharp-compiled-var fsharp-custom-operator-with-pipe-regexp
-  (let ((op-chars "!%&\\*\\+\\-\\./<=>@\\^~") ;; all F# custom operator chars except for `|`
-        (backward-pipe "<|\\{1,3\\}")
-        (forward-pipe "|\\{1,3\\}>")
-        (alt "\\|"))
-    (concat "[" op-chars "|]*" backward-pipe "[" op-chars  "]+"
-            alt "[" op-chars "|]+" backward-pipe "[" op-chars  "]*"
-            alt "[" op-chars  "]*" forward-pipe  "[" op-chars "|]+"
-            alt "[" op-chars  "]+" forward-pipe  "[" op-chars "|]*"))
-  "Match operators that contains pipe sequence -- <|>, |>>, <<|, etc.")
+                         (let ((op-chars "!%&\\*\\+\\-\\./<=>@\\^~") ;; all F# custom operator chars except for `|`
+                               (backward-pipe "<|\\{1,3\\}")
+                               (forward-pipe "|\\{1,3\\}>")
+                               (alt "\\|"))
+                           (concat "[" op-chars "|]*" backward-pipe "[" op-chars  "]+"
+                                   alt "[" op-chars "|]+" backward-pipe "[" op-chars  "]*"
+                                   alt "[" op-chars  "]*" forward-pipe  "[" op-chars "|]+"
+                                   alt "[" op-chars  "]+" forward-pipe  "[" op-chars "|]*"))
+                         "Match operators that contains pipe sequence -- <|>, |>>, <<|, etc.")
 
 (def-fsharp-compiled-var fsharp-operator-case-regexp
-  "\\s-+\\(|\\)[A-Za-z0-9_' ]"
-  "Match literal | in contexts like match and type declarations.")
+                         "\\s-+\\(|\\)[A-Za-z0-9_' ]"
+                         "Match literal | in contexts like match and type declarations.")
 
 (defvar fsharp-imenu-generic-expression
   `((nil                 ,(concat "^\\s-*" fsharp-function-def-regexp) 1)
@@ -215,52 +215,52 @@ with initial value INITVALUE and optional DOCSTRING."
 
 ;; Preprocessor directives (3.3)
 (def-fsharp-compiled-var fsharp-ui-preproessor-directives
-  '("#if" "#else" "#endif" "#light"))
+                         '("#if" "#else" "#endif" "#light"))
 
 ;; Compiler directives (12.4)
 (def-fsharp-compiled-var fsharp-ui-compiler-directives
-  '("#nowarn" "#load" "#r" "#reference" "#I"
-    "#Include" "#q" "#quit" "#time" "#help"))
+                         '("#nowarn" "#load" "#r" "#reference" "#I"
+                           "#Include" "#q" "#quit" "#time" "#help"))
 
 ;; Lexical matters (18.4)
 (def-fsharp-compiled-var fsharp-ui-lexical-matters
-  '("#indent"))
+                         '("#indent"))
 
 ;; Line Directives (3.9)
 (def-fsharp-compiled-var fsharp-ui-line-directives
-  '("#line"))
+                         '("#line"))
 
 ;; Identifier replacements (3.11)
 (def-fsharp-compiled-var fsharp-ui-identifier-replacements
-  '("__SOURCE_DIRECTORY__" "__SOURCE_FILE__" "__LINE__"))
+                         '("__SOURCE_DIRECTORY__" "__SOURCE_FILE__" "__LINE__"))
 
 ;; F# keywords (5.0)
 (def-fsharp-compiled-var fsharp-ui-fsharp-threefour-keywords
-  '("abstract" "and" "and!" "as" "assert" "base" "begin"
-    "class" "default" "delegate" "do" "do!" "done"
-    "downcast" "downto" "elif" "else" "end"
-    "exception" "extern" "false" "finally" "for" "fun"
-    "function" "global" "if" "in" "inherit" "inline"
-    "interface" "internal" "lazy" "let" "let!"
-    "match" "match!" "member" "module" "mutable" "namespace"
-    "new" "not" "null" "of" "open" "or" "override"
-    "private" "public" "rec" "return" "return!"
-    "select" "static" "struct" "then" "to" "true"
-    "try" "type" "upcast" "use" "use!"  "val" "void"
-    "when" "while" "with" "yield" "yield!"))
+                         '("abstract" "and" "and!" "as" "assert" "base" "begin"
+                           "class" "default" "delegate" "do" "do!" "done"
+                           "downcast" "downto" "elif" "else" "end"
+                           "exception" "extern" "false" "finally" "for" "fun"
+                           "function" "global" "if" "in" "inherit" "inline"
+                           "interface" "internal" "lazy" "let" "let!"
+                           "match" "match!" "member" "module" "mutable" "namespace"
+                           "new" "not" "null" "of" "open" "or" "override"
+                           "private" "public" "rec" "return" "return!"
+                           "select" "static" "struct" "then" "to" "true"
+                           "try" "type" "upcast" "use" "use!"  "val" "void"
+                           "when" "while" "with" "yield" "yield!"))
 
 ;; "Reserved because they are reserved in OCaml"
 (def-fsharp-compiled-var fsharp-ui-ocaml-reserved-words
-  '("asr" "land" "lor" "lsl" "lsr" "lxor" "mod" "sig"))
+                         '("asr" "land" "lor" "lsl" "lsr" "lxor" "mod" "sig"))
 
 ;; F# reserved words for future use
 (def-fsharp-compiled-var fsharp-ui-reserved-words
-  '("atomic" "break" "checked" "component" "const"
-    "constraint" "constructor" "continue" "eager"
-    "event" "external" "fixed" "functor" "include"
-    "method" "mixin" "object" "parallel" "process"
-    "protected" "pure" "sealed" "tailcall" "trait"
-    "virtual" "volatile"))
+                         '("atomic" "break" "checked" "component" "const"
+                           "constraint" "constructor" "continue" "eager"
+                           "event" "external" "fixed" "functor" "include"
+                           "method" "mixin" "object" "parallel" "process"
+                           "protected" "pure" "sealed" "tailcall" "trait"
+                           "virtual" "volatile"))
 
 ;; RMD 2016-09-30 -- This was pulled out separately with the following comment
 ;; when I got here. Not clear to me why it's on it's own, or even precisely what
@@ -270,21 +270,21 @@ with initial value INITVALUE and optional DOCSTRING."
 ;; Workflows not yet handled by fsautocomplete but async
 ;; always present
 (def-fsharp-compiled-var fsharp-ui-async-words
-  '("async")
-  "Just the word async, in a list.")
+                         '("async")
+                         "Just the word async, in a list.")
 
 (def-fsharp-compiled-var fsharp-ui-word-list-regexp
-  (regexp-opt
-   `(,@fsharp-ui-async-words
-     ,@fsharp-ui-compiler-directives
-     ,@fsharp-ui-fsharp-threefour-keywords
-     ,@fsharp-ui-identifier-replacements
-     ,@fsharp-ui-lexical-matters
-     ,@fsharp-ui-ocaml-reserved-words
-     ,@fsharp-ui-preproessor-directives
-     ,@fsharp-ui-reserved-words
-     ,@fsharp-ui-line-directives)
-   'symbols))
+                         (regexp-opt
+                          `(,@fsharp-ui-async-words
+                            ,@fsharp-ui-compiler-directives
+                            ,@fsharp-ui-fsharp-threefour-keywords
+                            ,@fsharp-ui-identifier-replacements
+                            ,@fsharp-ui-lexical-matters
+                            ,@fsharp-ui-ocaml-reserved-words
+                            ,@fsharp-ui-preproessor-directives
+                            ,@fsharp-ui-reserved-words
+                            ,@fsharp-ui-line-directives)
+                          'symbols))
 
 (defconst fsharp-font-lock-keywords
   (eval-when-compile
diff --git a/test/fsharp-mode-font-tests.el b/test/fsharp-mode-font-tests.el
index 55397f4..55eb423 100644
--- a/test/fsharp-mode-font-tests.el
+++ b/test/fsharp-mode-font-tests.el
@@ -24,19 +24,19 @@ then run BODY."
   (face-at-point))
 
 (describe "When locking operators"
-  (it "uses ui operator face for pipes"
-    (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
-      (should (equal (str-face " |> ") 'fsharp-ui-operator-face))
-      (should (equal (str-face " ||> ") 'fsharp-ui-operator-face))
-      (should (equal (str-face " |||> ") 'fsharp-ui-operator-face))
-      (should (equal (str-face " <| ") 'fsharp-ui-operator-face))
-      (should (equal (str-face " <|| ") 'fsharp-ui-operator-face))
-      (should (equal (str-face " <||| ") 'fsharp-ui-operator-face)))))
+          (it "uses ui operator face for pipes"
+              (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
+                                (should (equal (str-face " |> ") 'fsharp-ui-operator-face))
+                                (should (equal (str-face " ||> ") 'fsharp-ui-operator-face))
+                                (should (equal (str-face " |||> ") 'fsharp-ui-operator-face))
+                                (should (equal (str-face " <| ") 'fsharp-ui-operator-face))
+                                (should (equal (str-face " <|| ") 'fsharp-ui-operator-face))
+                                (should (equal (str-face " <||| ") 'fsharp-ui-operator-face)))))
 
 (describe "When locking operators"
-  (it "uses ui generic face for custom operators containing pipes"
-    (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
-      (should (equal (str-face "<<| ") 'fsharp-ui-generic-face))
-      (should (equal (str-face " |>> ") 'fsharp-ui-generic-face))
-      (should (equal (str-face " <|> ") 'fsharp-ui-generic-face))
-      (should (equal (str-face " <<|!") 'fsharp-ui-generic-face)))))
+          (it "uses ui generic face for custom operators containing pipes"
+              (with-highlighted "<<| |>> |> ||> |||> <| <|| <||| <|> <<|!"
+                                (should (equal (str-face "<<| ") 'fsharp-ui-generic-face))
+                                (should (equal (str-face " |>> ") 'fsharp-ui-generic-face))
+                                (should (equal (str-face " <|> ") 'fsharp-ui-generic-face))
+                                (should (equal (str-face " <<|!") 'fsharp-ui-generic-face)))))
diff --git a/test/fsharp-mode-structure-tests.el b/test/fsharp-mode-structure-tests.el
index a5b9da1..dd6653b 100644
--- a/test/fsharp-mode-structure-tests.el
+++ b/test/fsharp-mode-structure-tests.el
@@ -53,46 +53,46 @@
 ;;-------------------------------- Predicates --------------------------------;;
 
 (describe "The `fsharp-backslash-continuation-line-p' predicate"
-  (it "returns true when we expect it to"
-    (let ((file (file-truename (concat fsharp-struct-test-files-dir "ContinuationLines.fs"))))
-      (with-current-buffer (find-file-noselect file)
-	(beginning-of-buffer)
-	(should (eq (fsharp--hanging-operator-continuation-line-p) nil))
-	(forward-line 1)
-	(should (eq (fsharp--hanging-operator-continuation-line-p) nil))
-	(forward-line 5)
-	(should (eq (fsharp--hanging-operator-continuation-line-p) t))))))
+          (it "returns true when we expect it to"
+              (let ((file (file-truename (concat fsharp-struct-test-files-dir "ContinuationLines.fs"))))
+                (with-current-buffer (find-file-noselect file)
+	          (beginning-of-buffer)
+	          (should (eq (fsharp--hanging-operator-continuation-line-p) nil))
+	          (forward-line 1)
+	          (should (eq (fsharp--hanging-operator-continuation-line-p) nil))
+	          (forward-line 5)
+	          (should (eq (fsharp--hanging-operator-continuation-line-p) t))))))
 
 (describe "The `fsharp-in-literal-p'"
-  (it "return non-nil in both strings and comments?"
-    (let ((literals-file (file-truename (concat fsharp-struct-test-files-dir "Literals.fs"))))
-      (with-current-buffer (find-file-noselect  literals-file)
-	;; Comments
-	(goto-char 3)
-	(should (eq (fsharp-in-literal-p) 'comment))
-	(goto-char 642)
-	(should (eq (fsharp-in-literal-p) 'comment))
-	(goto-char 968)
-	(should (eq (fsharp-in-literal-p) 'comment))
-	(goto-char 1481)
-	(should (eq (fsharp-in-literal-p) 'comment))
-	(goto-char 2124)
-	(should (eq (fsharp-in-literal-p) 'comment))
-	;; String literals
-	(goto-char 2717)
-	(should (eq (fsharp-in-literal-p) 'string))
-	;; This string contains an inner, backslash-escaped string.
-	;; First, with point outside the backslash-escaped string:
-	(goto-char 2759)
-	(should (eq (fsharp-in-literal-p) 'string))
-	;; ...and now with point inside it
-	(goto-char 2774)
-	(should (eq (fsharp-in-literal-p) 'string))
-	;; Inside triple-quoted strings
-	(goto-char 2835)
-	(should (eq (fsharp-in-literal-p) 'string))
-	(goto-char 2900)
-	(should (eq (fsharp-in-literal-p) 'string))))))
+          (it "return non-nil in both strings and comments?"
+              (let ((literals-file (file-truename (concat fsharp-struct-test-files-dir "Literals.fs"))))
+                (with-current-buffer (find-file-noselect  literals-file)
+	          ;; Comments
+	          (goto-char 3)
+	          (should (eq (fsharp-in-literal-p) 'comment))
+	          (goto-char 642)
+	          (should (eq (fsharp-in-literal-p) 'comment))
+	          (goto-char 968)
+	          (should (eq (fsharp-in-literal-p) 'comment))
+	          (goto-char 1481)
+	          (should (eq (fsharp-in-literal-p) 'comment))
+	          (goto-char 2124)
+	          (should (eq (fsharp-in-literal-p) 'comment))
+	          ;; String literals
+	          (goto-char 2717)
+	          (should (eq (fsharp-in-literal-p) 'string))
+	          ;; This string contains an inner, backslash-escaped string.
+	          ;; First, with point outside the backslash-escaped string:
+	          (goto-char 2759)
+	          (should (eq (fsharp-in-literal-p) 'string))
+	          ;; ...and now with point inside it
+	          (goto-char 2774)
+	          (should (eq (fsharp-in-literal-p) 'string))
+	          ;; Inside triple-quoted strings
+	          (goto-char 2835)
+	          (should (eq (fsharp-in-literal-p) 'string))
+	          (goto-char 2900)
+	          (should (eq (fsharp-in-literal-p) 'string))))))
 
 ;; NOTE[gastove|2019-10-31] I am entirely convinced this doesn't work precisely
 ;; as it should, because it depends on `fsharp-goto-beyond-final-line', which I
@@ -113,161 +113,161 @@
 ;;--------------------- Nesting and Indentation Functions ---------------------;;
 
 (describe "The `fsharp-nesting-level' function"
-  (it "returns nil when we expect it to"
-    (with-temp-buffer
-      (insert "let x = 5")
-      (end-of-buffer)
-      (should (eq (fsharp-nesting-level) nil)))))
+          (it "returns nil when we expect it to"
+              (with-temp-buffer
+                (insert "let x = 5")
+                (end-of-buffer)
+                (should (eq (fsharp-nesting-level) nil)))))
 
 (describe "The `fsharp-nesting-level' function"
-  :var ((file (file-truename (concat fsharp-struct-test-files-dir "Nesting.fs"))))
-  (it  "correctly return the point position of the opening pair closest to point"
-    ;; The character positions use here reference characters noted in comments in Nesting.fs
-    ;; Test a normal list
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 645)
-      (should (eq (fsharp-nesting-level) 640)))
-
-    ;; Get the opening bracket of an inner list from a single-line nested list
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 717)
-      (should (eq (fsharp-nesting-level) 706)))
-
-    ;; Opening bracket for a multi-line non-nested list
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 795)
-      (should (eq (fsharp-nesting-level) 777)))
-
-    ;; Inner most opening bracket for a multi-line multi-nested list
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 960)
-      (should (eq (fsharp-nesting-level) 955)))
-    ;; Middle opening bracket for same list as previous
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 954)
-      (should (eq (fsharp-nesting-level) 953)))
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 974)
-      (should (eq (fsharp-nesting-level) 953)))
-    ;; Outermost opening bracket for same list
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 977)
-      (should (eq (fsharp-nesting-level) 947)))
-
-    ;; Basic Async form, should return the opening {
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 1088)
-      (should (eq (fsharp-nesting-level) 1060)))
-    ;; Same async form, inner async call
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 1129)
-      (should (eq (fsharp-nesting-level) 1121)))
-
-    ;; Lambda, wrapped in parens, should return the opening (
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 1238)
-      (should (eq (fsharp-nesting-level) 1208)))))
+          :var ((file (file-truename (concat fsharp-struct-test-files-dir "Nesting.fs"))))
+          (it  "correctly return the point position of the opening pair closest to point"
+               ;; The character positions use here reference characters noted in comments in Nesting.fs
+               ;; Test a normal list
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 645)
+                 (should (eq (fsharp-nesting-level) 640)))
+
+               ;; Get the opening bracket of an inner list from a single-line nested list
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 717)
+                 (should (eq (fsharp-nesting-level) 706)))
+
+               ;; Opening bracket for a multi-line non-nested list
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 795)
+                 (should (eq (fsharp-nesting-level) 777)))
+
+               ;; Inner most opening bracket for a multi-line multi-nested list
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 960)
+                 (should (eq (fsharp-nesting-level) 955)))
+               ;; Middle opening bracket for same list as previous
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 954)
+                 (should (eq (fsharp-nesting-level) 953)))
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 974)
+                 (should (eq (fsharp-nesting-level) 953)))
+               ;; Outermost opening bracket for same list
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 977)
+                 (should (eq (fsharp-nesting-level) 947)))
+
+               ;; Basic Async form, should return the opening {
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 1088)
+                 (should (eq (fsharp-nesting-level) 1060)))
+               ;; Same async form, inner async call
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 1129)
+                 (should (eq (fsharp-nesting-level) 1121)))
+
+               ;; Lambda, wrapped in parens, should return the opening (
+               (with-current-buffer (find-file-noselect file)
+                 (goto-char 1238)
+                 (should (eq (fsharp-nesting-level) 1208)))))
 
 
 (describe "The `fsharp--compute-indentaiton-open-bracket'"
-  :var ((file (file-truename (concat fsharp-struct-test-files-dir "BracketIndent.fs"))))
-  (it "returns the correct indentation in a variety of cases"
-    (with-current-buffer (find-file-noselect file)
-      ;; Opening bracket on same line as let, elements on same line; test element
-      (goto-char 44)
-      (let* ((nesting-level (fsharp-nesting-level))
-	     (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
-	;; The value we expect
-	(should (eq indent-at-point 18))
-	;; Both entrypoints should have the same answer
-	(should (eq indent-at-point (fsharp-compute-indentation t))))
-
-      ;; Opening bracket on same line as let, elements on same line; test newline
-      (goto-char 81)
-      (let* ((nesting-level (fsharp-nesting-level))
-	     (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
-	;; The value we expect
-	(should (eq indent-at-point 18))
-	;; Both entrypoints should have the same answer
-	(should (eq indent-at-point (fsharp-compute-indentation t))))
-
-      ;; Opening bracket on same line as let, elements on new line; test element
-      (goto-char 148)
-      (let* ((nesting-level (fsharp-nesting-level))
-	     (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
-	(should (eq indent-at-point 4))
-	(should (eq indent-at-point (fsharp-compute-indentation t))))
-
-      ;; Opening bracket on same line as let, elements on new line; test newline
-      (goto-char 155)
-      (let* ((nesting-level (fsharp-nesting-level))
-	     (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
-	(should (eq indent-at-point 4))
-	(should (eq indent-at-point (fsharp-compute-indentation t))))
-
-      ;; Opening bracket on own line; test element
-      (goto-char 231)
-      (let* ((nesting-level (fsharp-nesting-level))
-	     (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
-	(should (eq indent-at-point 6))
-	(should (eq indent-at-point (fsharp-compute-indentation t))))
-
-      ;; Opening bracket on own line; test newline
-      (goto-char 236)
-      (let* ((nesting-level (fsharp-nesting-level))
-	     (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
-	(should (eq indent-at-point 6))
-	(should (eq indent-at-point (fsharp-compute-indentation t)))))))
+          :var ((file (file-truename (concat fsharp-struct-test-files-dir "BracketIndent.fs"))))
+          (it "returns the correct indentation in a variety of cases"
+              (with-current-buffer (find-file-noselect file)
+                ;; Opening bracket on same line as let, elements on same line; test element
+                (goto-char 44)
+                (let* ((nesting-level (fsharp-nesting-level))
+	               (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
+	          ;; The value we expect
+	          (should (eq indent-at-point 18))
+	          ;; Both entrypoints should have the same answer
+	          (should (eq indent-at-point (fsharp-compute-indentation t))))
+
+                ;; Opening bracket on same line as let, elements on same line; test newline
+                (goto-char 81)
+                (let* ((nesting-level (fsharp-nesting-level))
+	               (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
+	          ;; The value we expect
+	          (should (eq indent-at-point 18))
+	          ;; Both entrypoints should have the same answer
+	          (should (eq indent-at-point (fsharp-compute-indentation t))))
+
+                ;; Opening bracket on same line as let, elements on new line; test element
+                (goto-char 148)
+                (let* ((nesting-level (fsharp-nesting-level))
+	               (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
+	          (should (eq indent-at-point 4))
+	          (should (eq indent-at-point (fsharp-compute-indentation t))))
+
+                ;; Opening bracket on same line as let, elements on new line; test newline
+                (goto-char 155)
+                (let* ((nesting-level (fsharp-nesting-level))
+	               (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
+	          (should (eq indent-at-point 4))
+	          (should (eq indent-at-point (fsharp-compute-indentation t))))
+
+                ;; Opening bracket on own line; test element
+                (goto-char 231)
+                (let* ((nesting-level (fsharp-nesting-level))
+	               (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
+	          (should (eq indent-at-point 6))
+	          (should (eq indent-at-point (fsharp-compute-indentation t))))
+
+                ;; Opening bracket on own line; test newline
+                (goto-char 236)
+                (let* ((nesting-level (fsharp-nesting-level))
+	               (indent-at-point (fsharp--compute-indentation-open-bracket nesting-level)))
+	          (should (eq indent-at-point 6))
+	          (should (eq indent-at-point (fsharp-compute-indentation t)))))))
 
 
 (describe "The `fsharp--compute-indentation-continuation-line' function"
-  :var ((continuation-line "let x = 5 +"))
-  (it "indents correctly"
-    (with-temp-buffer
-      (fsharp-mode)
-      (insert continuation-line)
-      (fsharp-newline-and-indent)
-      (should (eq (fsharp--compute-indentation-continuation-line) 8))
-      (should (eq (fsharp--compute-indentation-continuation-line) (fsharp-compute-indentation t))))))
+          :var ((continuation-line "let x = 5 +"))
+          (it "indents correctly"
+              (with-temp-buffer
+                (fsharp-mode)
+                (insert continuation-line)
+                (fsharp-newline-and-indent)
+                (should (eq (fsharp--compute-indentation-continuation-line) 8))
+                (should (eq (fsharp--compute-indentation-continuation-line) (fsharp-compute-indentation t))))))
 
 
 (describe "The `fsharp-compute-indentation-relative-to-previous' function'"
-  :var ((file (concat fsharp-struct-test-files-dir "Relative.fs")))
-  (it "indents correctly releative to previous line"
-    ;; Discriminated unions
-    (with-current-buffer (find-file-noselect file)
-      (goto-char 57)
-      (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
-      (should (eq (fsharp--compute-indentation-relative-to-previous t)
-		  (fsharp-compute-indentation t)))
-
-      ;; If/Else blocks
-      ;; if an if then are on the same line, the next line is indented
-      (goto-char 96)
-      (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
-      (should (eq (fsharp--compute-indentation-relative-to-previous t)
-		  (fsharp-compute-indentation t)))
-
-      ;; An else is not indented further; *however*, the indentation relative to
-      ;; previous will be 4, but `fsharp-compute-indentation' will return 0
-      ;; because the previous line is not a continuation line.
-      ;;
-      ;; However! This test case doesn't currently work. Indentation code
-      ;; produces indent of 0, but the compute indentation functions proudce an
-      ;; indent of 4, which is wrong.
-      ;;
-      ;; (goto-char 124)
-      ;; (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
-      ;; (should-not (eq (fsharp--compute-indentation-relative-to-previous t)
-      ;;                 (fsharp-compute-indentation t)))
-
-      ;; when a then is on its own line, the next line is indented
-      (goto-char 154)
-      (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
-      (should (eq (fsharp--compute-indentation-relative-to-previous t)
-		  (fsharp-compute-indentation t)))
-      ;; likewise an else
-      (goto-char 180)
-      (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
-      (should (eq (fsharp--compute-indentation-relative-to-previous t)
-		  (fsharp-compute-indentation t))))))
+          :var ((file (concat fsharp-struct-test-files-dir "Relative.fs")))
+          (it "indents correctly releative to previous line"
+              ;; Discriminated unions
+              (with-current-buffer (find-file-noselect file)
+                (goto-char 57)
+                (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
+                (should (eq (fsharp--compute-indentation-relative-to-previous t)
+		            (fsharp-compute-indentation t)))
+
+                ;; If/Else blocks
+                ;; if an if then are on the same line, the next line is indented
+                (goto-char 96)
+                (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
+                (should (eq (fsharp--compute-indentation-relative-to-previous t)
+		            (fsharp-compute-indentation t)))
+
+                ;; An else is not indented further; *however*, the indentation relative to
+                ;; previous will be 4, but `fsharp-compute-indentation' will return 0
+                ;; because the previous line is not a continuation line.
+                ;;
+                ;; However! This test case doesn't currently work. Indentation code
+                ;; produces indent of 0, but the compute indentation functions proudce an
+                ;; indent of 4, which is wrong.
+                ;;
+                ;; (goto-char 124)
+                ;; (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
+                ;; (should-not (eq (fsharp--compute-indentation-relative-to-previous t)
+                ;;                 (fsharp-compute-indentation t)))
+
+                ;; when a then is on its own line, the next line is indented
+                (goto-char 154)
+                (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
+                (should (eq (fsharp--compute-indentation-relative-to-previous t)
+		            (fsharp-compute-indentation t)))
+                ;; likewise an else
+                (goto-char 180)
+                (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
+                (should (eq (fsharp--compute-indentation-relative-to-previous t)
+		            (fsharp-compute-indentation t))))))
diff --git a/test/integration-tests.el b/test/integration-tests.el
index 1646876..74c1ccd 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -1,6 +1,6 @@
 ;;; integration-tests.el ---                         -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019  Jürgen Hötzel
+;; Copyright (C) 2019-2022  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Keywords: abbrev, abbrev
@@ -30,61 +30,63 @@
 
 (defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
   (eglot--sniffing (:server-notifications s-notifs)
-    (eglot--wait-for (s-notifs 20)
-                     (&key _id method params &allow-other-keys)
-                     (and
-                      (string= method "textDocument/publishDiagnostics")
-                      (string-suffix-p file-name-suffix (plist-get params :uri))))))
+                   (eglot--wait-for (s-notifs 20)
+                                    (&key _id method params &allow-other-keys)
+                                    (and
+                                     (string= method "textDocument/publishDiagnostics")
+                                     (string-suffix-p file-name-suffix (plist-get params :uri))))))
 
 (describe "F# LSP server"
-  (it "can be installed @version 0.52.0"
-    (eglot-fsharp--maybe-install "0.52.0")
-    (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
-  (it "Can be installed"
-    (eglot-fsharp--maybe-install)
-    (expect (eglot-fsharp--installed-version) :to-equal (eglot-fsharp--latest-version)))
-  (it "Can be invoked"
-      ;; FIXME: Should use dotnet tool run
-      (expect (car (process-lines (eglot-fsharp--path-to-server) "--version"))
-	      :to-match (rx line-start (? "FsAutoComplete" (1+ space)) (eval (eglot-fsharp--installed-version)))))
-  (it "shows flymake errors"
-    (with-current-buffer (eglot--find-file-noselect "test/Test1/Error.fs")
-      (eglot--tests-connect 10)
-      (search-forward "nonexisting")
-      (flymake-mode t)
-      (flymake-start)
-      (goto-char (point-min))
-      (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
-      (flymake-goto-next-error 1 '() t)
-      (expect (face-at-point) :to-be 'flymake-error )))
-  (it "is enabled on F# Files"
-    (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
-      (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
-  (it "provides completion"
-    (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
-      (eglot-fsharp--sniff-diagnostics "test/Test1/FileTwo.fs")
-      (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))
-  (it "completes function in other modules"
-    (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-      (search-forward "X.func")
-      (delete-char -3)
-      (eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
-      (completion-at-point)
-      (expect (looking-back "X\\.func") :to-be t)))
-  (it "finds definition in pervasives"
-      (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-	(eglot--tests-connect 10)
-	(search-forward "printfn")
-	(eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
-	(expect (current-word) :to-equal "printfn") ;sanity check
-	(call-interactively #'xref-find-definitions)
-	(expect (file-name-nondirectory (buffer-file-name)) :to-equal "fslib-extra-pervasives.fs")))
-  (it "finds definitions in other files of Project"
-    (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-      (goto-char 150)
-      (expect (current-word) :to-equal "NewObjectType") ;sanity check
-      (call-interactively #'xref-find-definitions)
-      (expect (file-name-nondirectory (buffer-file-name)) :to-equal "FileTwo.fs"))))
+	  :var (latest-version)
+	  :before-all (setq latest-version (eglot-fsharp--latest-version))
+          (it "can be installed @version 0.52.0"
+              (eglot-fsharp--maybe-install "0.52.0")
+              (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
+          (it (format "Can be installed (using latest version: %s)" latest-version)
+              (eglot-fsharp--maybe-install)
+              (expect (eglot-fsharp--installed-version) :to-equal latest-version))
+          (it "Can be invoked"
+              ;; FIXME: Should use dotnet tool run
+              (expect (car (process-lines (eglot-fsharp--path-to-server) "--version"))
+	              :to-match (rx line-start (? "FsAutoComplete" (1+ space)) (eval (eglot-fsharp--installed-version)))))
+          (it "shows flymake errors"
+              (with-current-buffer (eglot--find-file-noselect "test/Test1/Error.fs")
+                (eglot--tests-connect 10)
+                (search-forward "nonexisting")
+                (flymake-mode t)
+                (flymake-start)
+                (goto-char (point-min))
+                (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
+                (flymake-goto-next-error 1 '() t)
+                (expect (face-at-point) :to-be 'flymake-error )))
+          (it "is enabled on F# Files"
+              (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
+                (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
+          (it "provides completion"
+              (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
+                (eglot-fsharp--sniff-diagnostics "test/Test1/FileTwo.fs")
+                (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))
+          (it "completes function in other modules"
+              (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+                (search-forward "X.func")
+                (delete-char -3)
+                (eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
+                (completion-at-point)
+                (expect (looking-back "X\\.func") :to-be t)))
+          (it "finds definition in pervasives"
+              (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+	        (eglot--tests-connect 10)
+	        (search-forward "printfn")
+	        (eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
+	        (expect (current-word) :to-equal "printfn") ;sanity check
+	        (call-interactively #'xref-find-definitions)
+	        (expect (file-name-nondirectory (buffer-file-name)) :to-equal "fslib-extra-pervasives.fs")))
+          (it "finds definitions in other files of Project"
+              (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
+                (goto-char 150)
+                (expect (current-word) :to-equal "NewObjectType") ;sanity check
+                (call-interactively #'xref-find-definitions)
+                (expect (file-name-nondirectory (buffer-file-name)) :to-equal "FileTwo.fs"))))
 
 (provide 'integration-tests)
 ;;; integration-tests.el ends here

From a2f8d581dc7e158d22f4df4de54c7994ed31b53e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 5 Jun 2022 15:28:31 +0200
Subject: [PATCH 101/147] Update copyright/maintainer

---
 eglot-fsharp.el          | 4 ++--
 fsharp-mode-structure.el | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 30ab7e1..7656ec2 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -1,8 +1,8 @@
 ;;; eglot-fsharp.el --- fsharp-mode eglot integration                     -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019-2021  Jürgen Hötzel
+;; Copyright (C) 2019-2022  Jürgen Hötzel
 
-;; Author: Jürgen Hötzel <juergen@archlinux.org>
+;; Author: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Package-Requires: ((emacs "27.1") (eglot "1.4") (fsharp-mode "1.10") (jsonrpc "1.0.14"))
 ;; Version: 1.10
 ;; Keywords: languages
diff --git a/fsharp-mode-structure.el b/fsharp-mode-structure.el
index 2fb1a04..674f612 100644
--- a/fsharp-mode-structure.el
+++ b/fsharp-mode-structure.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2010 Laurent Le Brun
 
 ;; Author: 2010-2011 Laurent Le Brun <laurent@le-brun.eu>
-;; Maintainer: Robin Neatherway <robin.neatherway@gmail.com>
+;; Maintainer: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Keywords: languages
 
 ;; This file is not part of GNU Emacs.

From fc92b95c45a692283b8a0d643443f7decd302fff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 5 Jun 2022 15:39:13 +0200
Subject: [PATCH 102/147] Replace Cask with Eldev

- Remove Makefile use Eldev to download Eglot test helpers.
- Use Eldev in GH Actions
---
 .github/workflows/test.yml | 33 ++++++++++++++++++-------------
 Cask                       |  9 ---------
 Eldev                      | 20 +++++++++++++++++++
 Makefile                   | 40 --------------------------------------
 4 files changed, 39 insertions(+), 63 deletions(-)
 delete mode 100644 Cask
 create mode 100644 Eldev
 delete mode 100644 Makefile

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c04d1e6..36042c7 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -26,20 +26,27 @@ jobs:
       with:
         dotnet-version: ${{ matrix.dotnet }}
     - uses: actions/checkout@v2
-    - uses: conao3/setup-cask@master
+    - name: Install Eldev
+      run: curl -fsSL https://raw.github.com/doublep/eldev/master/webinstall/github-eldev | sh
     - name: Show dotnet sdks
       run: dotnet --list-sdks
     - name: Show dotnet version
       run: dotnet --info
     - name: Test
-      run: make test
+      run: |
+        echo "Archives:"
+        eldev archives
+        echo "Dependencies:"
+        eldev -v dependencies
+        echo "Testing:"
+        eldev -dtT test
   windows-build:
     runs-on: windows-latest
     strategy:
       fail-fast: false
     steps:
     - uses: actions/setup-dotnet@v1
-    - name: Install Cask/scoop-emacs
+    - name: Install scoop-emacs
       run: |
         Set-ExecutionPolicy RemoteSigned -scope CurrentUser
         Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
@@ -49,15 +56,13 @@ jobs:
         scoop install make
         echo "$env:PATH" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
     - uses: actions/checkout@v2
-    - name: Test                # FIXME: cask hack
+    - name: Install Eldev
+      run: curl.exe -fsSL https://raw.github.com/doublep/eldev/master/webinstall/eldev.bat | cmd /Q
+    - name: Test
       run: |
-        git clone https://github.com/tom-bowles/cask cask-windows
-        Remove-Item -recurse .\cask-windows\test
-        dotnet restore test/Test1
-        Invoke-WebRequest -Uri https://raw.githubusercontent.com/joaotavora/eglot/master/eglot-tests.el -OutFile eglot-tests.el
-        Start .\Cask-windows\bin\cask.bat -ArgumentList install -NoNewWindow -Wait
-        Start .\Cask-windows\bin\cask.bat -ArgumentList build -NoNewWindow -Wait
-        Start .\Cask-windows\bin\cask.bat -ArgumentList "exec buttercup -L . -L test --traceback full" -NoNewWindow -Wait
-
-
-
+        echo "Archives:"
+        ~/.local/bin/eldev.bat archives
+        echo "Dependencies:"
+        ~/.local/bin/eldev.bat dependencies
+        echo "Testing:"
+        ~/.local/bin/eldev.bat -p -dtT test
diff --git a/Cask b/Cask
deleted file mode 100644
index cc6c144..0000000
--- a/Cask
+++ /dev/null
@@ -1,9 +0,0 @@
-(source gnu)
-(source melpa)
-
-(package-file "fsharp-mode.el")
-
-;; FIXME: Use multiple packages: https://github.com/melpa/melpa#example-multiple-packages-in-one-repository ?
-(development
- (depends-on "buttercup")
- (depends-on "eglot"))
diff --git a/Eldev b/Eldev
new file mode 100644
index 0000000..e134b54
--- /dev/null
+++ b/Eldev
@@ -0,0 +1,20 @@
+; -*- mode: emacs-lisp; lexical-binding: t -*-
+;; FIXME: Use if-modified-since header?
+(unless (and (file-exists-p "eglot-tests.el") (< (time-to-seconds (time-subtract (current-time)
+                                                                                 (file-attribute-modification-time (file-attributes "eglot-tests.el"))))
+                                                 86400))
+  (url-copy-file "https://raw.githubusercontent.com/joaotavora/eglot/master/eglot-tests.el" "eglot-tests.el" t))
+
+
+(setq package-lint-main-file "eglot-fsharp.el")
+(setq eldev-project-main-file "eglot-fsharp.el")
+
+(eldev-use-package-archive 'melpa-unstable)
+(eldev-use-package-archive 'gnu)
+(eldev-use-plugin 'autoloads)
+(setq package-archive-priorities
+      '(("melpa-unstable" . 400)
+	("gnu" . 300)))
+
+
+
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 75a67d8..0000000
--- a/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-all: build
-export EMACS ?= emacs
-EMACSFLAGS = -L .
-CASK = cask
-VERSION = $(shell git describe --tags --abbrev=0 | sed 's/^v//')
-PKG = fsharp-mode
-
-elpa-$(EMACS):
-	$(CASK) install
-	$(CASK) update
-	touch $@
-
-test/eglot-tests.el:
-	curl -o eglot-tests.el https://raw.githubusercontent.com/joaotavora/eglot/master/eglot-tests.el
-
-elpa: elpa-$(EMACS)
-
-build: elpa version
-	$(CASK) build
-
-version:
-	$(EMACS) --version
-
-test/Test1/restored:
-	dotnet restore test/Test1
-	touch test/Test1/restored
-
-test: version build test/eglot-tests.el test/Test1/restored
-	$(CASK) exec buttercup -L . -L ./test --traceback full
-
-clean:
-	rm -f .depend elpa-$(EMACS) $(OBJECTS) $(PKG)-autoloads.el
-
-elpaclean: clean
-	rm -f elpa*
-	rm -rf .cask # Clean packages installed for development
-
-run-$(PKG): elpa
-	cask exec $(EMACS) -Q -L . --eval "(require '$(PKG))"
-

From 77bea0547fdddec31d37c5d93f68da135b089099 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 5 Jun 2022 20:17:17 +0200
Subject: [PATCH 103/147] Refactor Integration tests

- Use single F# LSP session for all tests: The seems to be a race
condition when restarting the F# LSP session for each test.
- "dotnet restore" before running integration tests
- Use own util functions for eglot instead of downloading eglot-tests
- Fix flymake integration test:
  Need to notify `textDocument/didChange` to trigger diagnostics.
- Improve Debugging of integration tests:
  Output jsonrpc events buffer on timeout.
---
 Eldev                                 |   6 -
 test/eglot-fsharp-integration-util.el | 164 ++++++++++++++++++++++++++
 test/integration-tests.el             | 117 +++++++++---------
 3 files changed, 222 insertions(+), 65 deletions(-)
 create mode 100644 test/eglot-fsharp-integration-util.el

diff --git a/Eldev b/Eldev
index e134b54..6b01e5e 100644
--- a/Eldev
+++ b/Eldev
@@ -1,10 +1,4 @@
 ; -*- mode: emacs-lisp; lexical-binding: t -*-
-;; FIXME: Use if-modified-since header?
-(unless (and (file-exists-p "eglot-tests.el") (< (time-to-seconds (time-subtract (current-time)
-                                                                                 (file-attribute-modification-time (file-attributes "eglot-tests.el"))))
-                                                 86400))
-  (url-copy-file "https://raw.githubusercontent.com/joaotavora/eglot/master/eglot-tests.el" "eglot-tests.el" t))
-
 
 (setq package-lint-main-file "eglot-fsharp.el")
 (setq eldev-project-main-file "eglot-fsharp.el")
diff --git a/test/eglot-fsharp-integration-util.el b/test/eglot-fsharp-integration-util.el
new file mode 100644
index 0000000..2dca357
--- /dev/null
+++ b/test/eglot-fsharp-integration-util.el
@@ -0,0 +1,164 @@
+;;; eglot-fsharp-integration-util.el --- Helper for eglot integration tests  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022  Jürgen Hötzel
+
+;; Author: Jürgen Hötzel <juergen@hoetzel.info>
+;; Keywords: processes
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; 
+
+;;; Code:
+(require 'edebug)
+
+(cl-defmacro eglot-fsharp--with-timeout (timeout &body body)
+  (declare (indent 1) (debug t))
+  `(eglot-fsharp--call-with-timeout ,timeout (lambda () ,@body)))
+
+(defun eglot-fsharp--call-with-timeout (timeout fn)
+  (let* ((tag (gensym "eglot-test-timeout"))
+         (timed-out (make-symbol "timeout"))
+         (timeout-and-message
+          (if (listp timeout) timeout
+            (list timeout "waiting for test to finish")))
+         (timeout (car timeout-and-message))
+         (message (cadr timeout-and-message))
+         (timer)
+         (retval))
+    (unwind-protect
+        (setq retval
+              (catch tag
+                (setq timer
+                      (run-with-timer timeout nil
+                                      (lambda ()
+                                        (unless edebug-active
+                                          (throw tag timed-out)))))
+                (funcall fn)))
+      (cancel-timer timer)
+      (when (eq retval timed-out)
+        (warn "Received Events for %s : %s"
+              (file-name-nondirectory (buffer-file-name))
+              (with-current-buffer (jsonrpc-events-buffer (eglot-current-server)) (buffer-string)))
+        (error "%s" (concat "Timed out " message))))))
+
+
+(defun eglot-fsharp--find-file-noselect (file &optional noerror)
+  (unless (or noerror
+              (file-readable-p file)) (error "%s does not exist" file))
+  (find-file-noselect file))
+
+(defun eglot-fsharp--tests-connect (&optional timeout)
+  (let* ((timeout (or timeout 10))
+         (eglot-sync-connect t)
+         (eglot-connect-timeout timeout))
+    (apply #'eglot--connect (eglot--guess-contact))))
+
+(cl-defmacro eglot-fsharp--wait-for ((events-sym &optional (timeout 1) message) args &body body)
+  "Spin until FN match in EVENTS-SYM, flush events after it.
+Pass TIMEOUT to `eglot--with-timeout'."
+  (declare (indent 2) (debug (sexp sexp sexp &rest form)))
+  `(eglot-fsharp--with-timeout '(,timeout ,(or message
+                                        (format "waiting for:\n%s" (pp-to-string body))))
+     (let ((event
+            (cl-loop thereis (cl-loop for json in ,events-sym
+                                      for method = (plist-get json :method)
+                                      when (keywordp method)
+                                      do (plist-put json :method
+                                                    (substring
+                                                     (symbol-name method)
+                                                     1))
+                                      when (funcall
+                                            (jsonrpc-lambda ,args ,@body) json)
+                                      return (cons json before)
+                                      collect json into before)
+                     for i from 0
+                     when (zerop (mod i 5))
+                     ;; do (eglot--message "still struggling to find in %s"
+                     ;;                    ,events-sym)
+                     do
+                     ;; `read-event' is essential to have the file
+                     ;; watchers come through.
+                     (read-event "[eglot] Waiting a bit..." nil 0.1)
+                     (accept-process-output nil 0.1))))
+       (setq ,events-sym (cdr event))
+       (eglot--message "Event detected:\n%s"
+                       (pp-to-string (car event))))))
+
+
+(cl-defmacro eglot-fsharp--sniffing ((&key server-requests
+                                    server-notifications
+                                    server-replies
+                                    client-requests
+                                    client-notifications
+                                    client-replies)
+                              &rest body)
+  "Run BODY saving LSP JSON messages in variables, most recent first."
+  (declare (indent 1) (debug (sexp &rest form)))
+  (let ((log-event-ad-sym (make-symbol "eglot-fsharp--event-sniff")))
+    `(unwind-protect
+         (let ,(delq nil (list server-requests
+                               server-notifications
+                               server-replies
+                               client-requests
+                               client-notifications
+                               client-replies))
+           (advice-add
+            #'jsonrpc--log-event :before
+            (lambda (_proc message &optional type)
+              (cl-destructuring-bind (&key method id _error &allow-other-keys)
+                  message
+                (let ((req-p (and method id))
+                      (notif-p method)
+                      (reply-p id))
+                  (cond
+                   ((eq type 'server)
+                    (cond (req-p ,(when server-requests
+                                    `(push message ,server-requests)))
+                          (notif-p ,(when server-notifications
+                                      `(push message ,server-notifications)))
+                          (reply-p ,(when server-replies
+                                      `(push message ,server-replies)))))
+                   ((eq type 'client)
+                    (cond (req-p ,(when client-requests
+                                    `(push message ,client-requests)))
+                          (notif-p ,(when client-notifications
+                                      `(push message ,client-notifications)))
+                          (reply-p ,(when client-replies
+                                      `(push message ,client-replies)))))))))
+            '((name . ,log-event-ad-sym)))
+           ,@body)
+       (advice-remove #'jsonrpc--log-event ',log-event-ad-sym))))
+
+
+
+(defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
+  (eglot-fsharp--sniffing (:server-notifications s-notifs)
+                          (eglot-fsharp--wait-for (s-notifs 20)
+                                           (&key _id method params &allow-other-keys)
+                                           (and
+                                            (string= method "textDocument/publishDiagnostics")
+                                            (string-suffix-p file-name-suffix (plist-get params :uri))))))
+
+(defun eglot-fsharp--sniff-method (method-name)
+  (eglot-fsharp--sniffing (:server-notifications s-notifs)
+                          (eglot-fsharp--wait-for (s-notifs 20)
+                                           (&key _id method params &allow-other-keys)
+                                           (and
+                                            (string= method method-name)))))
+
+(provide 'eglot-fsharp-integration-util)
+;;; integration-util.el ends here
diff --git a/test/integration-tests.el b/test/integration-tests.el
index 74c1ccd..6c56867 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -26,67 +26,66 @@
 
 (require 'buttercup)
 (require 'eglot-fsharp)
-(require 'eglot-tests)
+(load "test/eglot-fsharp-integration-util.el")
 
-(defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
-  (eglot--sniffing (:server-notifications s-notifs)
-                   (eglot--wait-for (s-notifs 20)
-                                    (&key _id method params &allow-other-keys)
-                                    (and
-                                     (string= method "textDocument/publishDiagnostics")
-                                     (string-suffix-p file-name-suffix (plist-get params :uri))))))
+(describe "F# LSP Installation"
+  :before-all (setq latest-version (eglot-fsharp--latest-version))
+  (it "succeeds using version 0.52.0"
+    (eglot-fsharp--maybe-install "0.52.0")
+    (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
+  (it (format "succeeds using latest version: %s)" latest-version)
+    (eglot-fsharp--maybe-install)
+    (expect (eglot-fsharp--installed-version) :to-equal latest-version)))
+
+(describe "F# LSP Client"
+  :before-all (progn (setq latest-version (eglot-fsharp--latest-version))
+                     (with-temp-buffer (unless (zerop (process-file "dotnet"  nil (current-buffer) nil "restore" "test/Test1"))
+                                         (signal 'file-error (buffer-string))))
+                     (eglot-fsharp--maybe-install)
+                     (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
+                       (eglot-fsharp--tests-connect 10)
+                       (eglot-fsharp--sniff-method "fsharp/notifyWorkspace")))
+
+  (it "Can be invoked"
+    ;; FIXME: Should use dotnet tool run
+    (expect (process-file (eglot-fsharp--path-to-server) nil nil nil "--version")
+	    :to-equal 0))
+  (it "is enabled on F# Files"
+    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
+      (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
+  (it "shows flymake errors"
+    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Error.fs")
+      (flymake-mode t)
+      (flymake-start)
+      (goto-char (point-min))
+      (search-forward "nonexisting")
+      (insert "x")
+      (eglot--signal-textDocument/didChange)
+      (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
+      (flymake-goto-next-error 1 '() t)
+      (expect (face-at-point) :to-be 'flymake-error )))
+  (it "provides completion"
+    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
+      (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))
+  (it "completes function in other modules"
+    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Program.fs")
+      (search-forward "X.func")
+      (delete-char -3)
+      (completion-at-point)
+      (expect (looking-back "X\\.func") :to-be t)))
+  (it "finds definition in pervasives"
+    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Program.fs")
+      (search-forward "printfn")
+      (expect (current-word) :to-equal "printfn") ;sanity check
+      (call-interactively #'xref-find-definitions)
+      (expect (file-name-nondirectory (buffer-file-name)) :to-equal "fslib-extra-pervasives.fs")))
+  (it "finds definitions in other files of Project"
+    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Program.fs")
+      (goto-char 150)
+      (expect (current-word) :to-equal "NewObjectType") ;sanity check
+      (call-interactively #'xref-find-definitions)
+      (expect (file-name-nondirectory (buffer-file-name)) :to-equal "FileTwo.fs"))))
 
-(describe "F# LSP server"
-	  :var (latest-version)
-	  :before-all (setq latest-version (eglot-fsharp--latest-version))
-          (it "can be installed @version 0.52.0"
-              (eglot-fsharp--maybe-install "0.52.0")
-              (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
-          (it (format "Can be installed (using latest version: %s)" latest-version)
-              (eglot-fsharp--maybe-install)
-              (expect (eglot-fsharp--installed-version) :to-equal latest-version))
-          (it "Can be invoked"
-              ;; FIXME: Should use dotnet tool run
-              (expect (car (process-lines (eglot-fsharp--path-to-server) "--version"))
-	              :to-match (rx line-start (? "FsAutoComplete" (1+ space)) (eval (eglot-fsharp--installed-version)))))
-          (it "shows flymake errors"
-              (with-current-buffer (eglot--find-file-noselect "test/Test1/Error.fs")
-                (eglot--tests-connect 10)
-                (search-forward "nonexisting")
-                (flymake-mode t)
-                (flymake-start)
-                (goto-char (point-min))
-                (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
-                (flymake-goto-next-error 1 '() t)
-                (expect (face-at-point) :to-be 'flymake-error )))
-          (it "is enabled on F# Files"
-              (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
-                (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
-          (it "provides completion"
-              (with-current-buffer (eglot--find-file-noselect "test/Test1/FileTwo.fs")
-                (eglot-fsharp--sniff-diagnostics "test/Test1/FileTwo.fs")
-                (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))
-          (it "completes function in other modules"
-              (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-                (search-forward "X.func")
-                (delete-char -3)
-                (eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
-                (completion-at-point)
-                (expect (looking-back "X\\.func") :to-be t)))
-          (it "finds definition in pervasives"
-              (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-	        (eglot--tests-connect 10)
-	        (search-forward "printfn")
-	        (eglot-fsharp--sniff-diagnostics "test/Test1/Program.fs")
-	        (expect (current-word) :to-equal "printfn") ;sanity check
-	        (call-interactively #'xref-find-definitions)
-	        (expect (file-name-nondirectory (buffer-file-name)) :to-equal "fslib-extra-pervasives.fs")))
-          (it "finds definitions in other files of Project"
-              (with-current-buffer (eglot--find-file-noselect "test/Test1/Program.fs")
-                (goto-char 150)
-                (expect (current-word) :to-equal "NewObjectType") ;sanity check
-                (call-interactively #'xref-find-definitions)
-                (expect (file-name-nondirectory (buffer-file-name)) :to-equal "FileTwo.fs"))))
 
 (provide 'integration-tests)
 ;;; integration-tests.el ends here

From 07496d4c7b7b1f98de6a637628c9e1434ca44866 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 14:26:03 +0200
Subject: [PATCH 104/147] Integration test: reload "project.el"

Emacs 27.x Workaround: https://github.com/joaotavora/eglot/issues/549
---
 test/integration-tests.el | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 6c56867..2e4e790 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -24,6 +24,7 @@
 
 ;;; Code:
 
+(load "project")                        ;Emacs 27 workaround: https://github.com/joaotavora/eglot/issues/549
 (require 'buttercup)
 (require 'eglot-fsharp)
 (load "test/eglot-fsharp-integration-util.el")

From 0a05c5d38ab881da3c1678c58e2d583905a3ee99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 15:08:57 +0200
Subject: [PATCH 105/147] Use jcs090218/setup-emacs-windows for Windows CI

---
 .github/workflows/test.yml | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 36042c7..dbfd577 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -46,15 +46,10 @@ jobs:
       fail-fast: false
     steps:
     - uses: actions/setup-dotnet@v1
-    - name: Install scoop-emacs
-      run: |
-        Set-ExecutionPolicy RemoteSigned -scope CurrentUser
-        Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
-        scoop update
-        scoop bucket add extras
-        scoop install emacs
-        scoop install make
-        echo "$env:PATH" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
+    - name: Set up Emacs on Windows
+      uses: jcs090218/setup-emacs-windows@master
+      with:
+        version: 28.1
     - uses: actions/checkout@v2
     - name: Install Eldev
       run: curl.exe -fsSL https://raw.github.com/doublep/eldev/master/webinstall/eldev.bat | cmd /Q

From 91010b716f7898038e1b90cc15a77628122dfd68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 16:14:06 +0200
Subject: [PATCH 106/147] Integration tests: Don't install multiple versions on
 Windows:

fsautocomplete process don't seem to terminate: "Access denied" when
trying to install a different version.
---
 test/integration-tests.el | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 2e4e790..02a95a4 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -29,14 +29,17 @@
 (require 'eglot-fsharp)
 (load "test/eglot-fsharp-integration-util.el")
 
-(describe "F# LSP Installation"
-  :before-all (setq latest-version (eglot-fsharp--latest-version))
-  (it "succeeds using version 0.52.0"
-    (eglot-fsharp--maybe-install "0.52.0")
-    (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
-  (it (format "succeeds using latest version: %s)" latest-version)
-    (eglot-fsharp--maybe-install)
-    (expect (eglot-fsharp--installed-version) :to-equal latest-version)))
+;; FIXME/HELP WANTED: fsautocomplete process don't seem to terminate on windows (Access denied when trying to install
+;; different version)
+(unless (eq system-type 'windows-nt)
+  (describe "F# LSP Installation"
+            :before-all (setq latest-version (eglot-fsharp--latest-version))
+            (it "succeeds using version 0.52.0"
+                (eglot-fsharp--maybe-install "0.52.0")
+                (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
+            (it (format "succeeds using latest version: %s)" latest-version)
+                (eglot-fsharp--maybe-install)
+                (expect (eglot-fsharp--installed-version) :to-equal latest-version))))
 
 (describe "F# LSP Client"
   :before-all (progn (setq latest-version (eglot-fsharp--latest-version))

From 8d2ab2841701ef7c86d20430452cde66c46dad6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 16:32:27 +0200
Subject: [PATCH 107/147] signal stderr of "dotnet install" failure

Improves CI debugging
---
 eglot-fsharp.el | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 7656ec2..a53cba4 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -124,11 +124,11 @@
 
 (defun eglot-fsharp--process-tool-action (response)
   "Process the result of calling the dotnet tool installation returning RESPONSE code."
-  (if (eq response 1)
-      (let ((minibuffer-message-timeout 5)
-	    (msg (format "Error installing fsautocomplete see %s" (concat default-directory "error_output.txt")) ))
-	(minibuffer-message msg)
-	(error "Failed to install dotnet tool fsautocomplete"))))
+  (when (>= response 1)
+    (error "Failed to install dotnet tool fsautocomplete: %s"
+           (with-temp-buffer
+             (insert-file-contents "error_output.txt")
+             (buffer-string)))))
 
 (defun eglot-fsharp--install-core (version)
   "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."

From add296fcc5516cab79210c89ca9b049c971f7e85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 16:39:18 +0200
Subject: [PATCH 108/147] CI: Show dotnet version on Windows

---
 .github/workflows/test.yml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index dbfd577..ee6c908 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -46,6 +46,12 @@ jobs:
       fail-fast: false
     steps:
     - uses: actions/setup-dotnet@v1
+      with:
+        dotnet-version: 6.0.200
+    - name: Show dotnet sdks
+      run: dotnet --list-sdks
+    - name: Show dotnet version
+      run: dotnet --info
     - name: Set up Emacs on Windows
       uses: jcs090218/setup-emacs-windows@master
       with:

From 52c3c12b3590a0944dc837c126d4c602e9a07dc3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 16:48:21 +0200
Subject: [PATCH 109/147] Debug output: Show fsautocomplete version that will
 be installed

---
 eglot-fsharp.el | 1 +
 1 file changed, 1 insertion(+)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index a53cba4..6dfaa86 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -134,6 +134,7 @@
   "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."
   (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
     (unless (eglot-fsharp-current-version-p version)
+      (message "Installing fsautocomplete version %s" version)
       (if (file-exists-p (eglot-fsharp--path-to-server))
 	  (eglot-fsharp--process-tool-action	  (call-process "dotnet" nil '(nil
 									       "error_output.txt")

From 2381a07f97d8179850c2eca2c0ed69c3e89a3109 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 17:22:00 +0200
Subject: [PATCH 110/147] Use Nuget API instead of parsing output of "dotnet
 tool search"

Prevents parsing issues because of localisation (No LANG=C on Windows).
---
 eglot-fsharp.el | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 6dfaa86..c97a5cb 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -75,12 +75,10 @@
 
 (defun eglot-fsharp--latest-version ()
   "Return latest fsautocomplete.exe version."
-  (let ((process-environment (cons  "LANG=C" process-environment))) ;FIXME: Doesn't work in Windows
-    (if eglot-fsharp--latest-version
-        eglot-fsharp--latest-version
-      (setq eglot-fsharp--latest-version
-            (seq-some (lambda (s) (and (string-match "^[[:alnum:]]* Version: \\(.*\\)$" s) (match-string 1 s)))
-                      (process-lines "dotnet"  "tool" "search" "fsautocomplete" "--detail"))))))
+  (let* ((json (with-temp-buffer (url-insert-file-contents "https://azuresearch-usnc.nuget.org/query?q=fsautocomplete&prerelease=false&packageType=DotnetTool")
+			         (json-parse-buffer)))
+         (versions (gethash "versions" (aref (gethash "data" json) 0))))
+    (gethash "version" (aref versions (1- (length versions))))))
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."

From ab625668310bdf88390faa53c29eb5f2e90608f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 17:30:54 +0200
Subject: [PATCH 111/147] Run CI on PR only

---
 .github/workflows/test.yml | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ee6c908..e61c787 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,10 +1,6 @@
 name: "CI"
 on:
   pull_request:
-  push:
-    # Comment out this section to enable testing of all branches.
-    branches:
-      - master
 jobs:
   gnu-build:
     runs-on: ubuntu-latest

From 15964df7c65a3b46d704c85873619fec073eabc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sat, 18 Jun 2022 17:40:02 +0200
Subject: [PATCH 112/147] Revert "Run CI on PR only"

Required for CI badge:

This reverts commit ab625668310bdf88390faa53c29eb5f2e90608f9.
---
 .github/workflows/test.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e61c787..ee6c908 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,6 +1,10 @@
 name: "CI"
 on:
   pull_request:
+  push:
+    # Comment out this section to enable testing of all branches.
+    branches:
+      - master
 jobs:
   gnu-build:
     runs-on: ubuntu-latest

From 40db2e5fd5080989c7166cf7499ab286dc4b6c07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 19 Jun 2022 14:07:59 +0200
Subject: [PATCH 113/147] Refactor "dotnet tool (un)install fsautocomplete"
 error reporting

- Use temp-file instead of hardcoded stderr-file.
- Report the exact command that failed.
---
 eglot-fsharp.el | 46 ++++++++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index c97a5cb..5a92954 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -119,30 +119,32 @@
 	    (chmod file #o644)))))
     (delete-file zip)))
 
-
-(defun eglot-fsharp--process-tool-action (response)
-  "Process the result of calling the dotnet tool installation returning RESPONSE code."
-  (when (>= response 1)
-    (error "Failed to install dotnet tool fsautocomplete: %s"
-           (with-temp-buffer
-             (insert-file-contents "error_output.txt")
-             (buffer-string)))))
-
 (defun eglot-fsharp--install-core (version)
   "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."
-  (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
-    (unless (eglot-fsharp-current-version-p version)
-      (message "Installing fsautocomplete version %s" version)
-      (if (file-exists-p (eglot-fsharp--path-to-server))
-	  (eglot-fsharp--process-tool-action	  (call-process "dotnet" nil '(nil
-									       "error_output.txt")
-								nil "tool" "uninstall"
-								"fsautocomplete" "--tool-path"
-								default-directory)))
-      (eglot-fsharp--process-tool-action (call-process "dotnet" nil '(nil "error_output.txt") nil
-						       "tool" "install" "fsautocomplete"
-						       "--tool-path" default-directory "--version"
-						       version)))))
+  (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server)))
+        (stderr-file (make-temp-file "dotnet_stderr")))
+    (condition-case err
+        (progn
+          (unless (eglot-fsharp-current-version-p version)
+            (message "Installing fsautocomplete version %s" version)
+            (when (file-exists-p (eglot-fsharp--path-to-server))
+	      (unless (zerop (call-process "dotnet" nil `(nil
+							  ,stderr-file)
+					   nil "tool" "uninstall"
+					   "fsautocomplete" "--tool-path"
+					   default-directory))
+                (error  "'dotnet tool uninstall fsautocomplete --tool-path %s' failed" default-directory))))
+          (unless (zerop (call-process "dotnet" nil `(nil ,stderr-file) nil
+				       "tool" "install" "fsautocomplete"
+				       "--tool-path" default-directory "--version"
+				       version))
+            (error "'dotnet tool install fsautocomplete --tool-path %s --version ' failed" default-directory  version)))
+      (error
+       (let ((stderr (with-temp-buffer
+                       (insert-file-contents stderr-file)
+                       (buffer-string))))
+         (delete-file stderr-file)
+         (signal (car err) (format "%s: %s" (cdr err) stderr)))))))
 
 (defun eglot-fsharp--maybe-install (&optional version)
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."

From 7d828553fae1bf679e0d49409a6031f424922c34 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 19 Jun 2022 19:23:48 +0200
Subject: [PATCH 114/147] Add FSI tests

Refs #293
---
 test/fsi-tests.el | 73 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 test/fsi-tests.el

diff --git a/test/fsi-tests.el b/test/fsi-tests.el
new file mode 100644
index 0000000..c0b56ec
--- /dev/null
+++ b/test/fsi-tests.el
@@ -0,0 +1,73 @@
+;;; fsi-tests.el --- Tests for F# interactive        -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022  Jürgen Hötzel
+
+;; Author: Jürgen Hötzel <juergen@hoetzel.info>
+;; Keywords: processes
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; 
+
+;;; Code:
+
+(load "project")                        ;Emacs 27 workaround: https://github.com/joaotavora/eglot/issues/549
+(require 'buttercup)
+(require 'fsharp-mode)
+
+(defun fsi-tests-wait-for-regex (timeout regexp)
+  (while (and (> timeout 0) (not (progn (goto-char (point-min)) (search-forward-regexp regexp nil t))))
+    (message "[FSI Interactive] Waiting a bit...")
+    (accept-process-output (get-buffer-process (current-buffer)) 0.2)
+    (setq timeout (1- timeout))))
+
+
+(describe "F# interactive"
+          :before-all (run-fsharp inferior-fsharp-program)
+          :before-each (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
+                         (comint-clear-buffer))
+          (it "can eval expressions"
+              (let ((fsharp-autosave-on-file-load t)
+                    (fsx-file (make-temp-file "fsi" nil ".fsx" "
+1 + 1;;
+")))
+                (with-current-buffer (find-file-noselect fsx-file)
+                  (fsharp-eval-region (point-min) (point-max))
+                  (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
+                    (fsi-tests-wait-for-regex 25 "it: int = 2$")
+                    (let ((result (match-string-no-properties 0)))
+                      (expect result :to-equal "it: int = 2"))))))
+          (it "can load nuget references"
+              (let ((fsharp-autosave-on-file-load t)
+                    (timeout 50)
+                    (fsx-file (make-temp-file "fsi" nil ".fsx" "
+#r \"nuget: Newtonsoft.Json\";;
+open Newtonsoft.Json;;
+
+let o = {| X = 2; Y = \"Hello\" |};;
+
+printfn \"xxx:%s:xxx\" (JsonConvert.SerializeObject o);;")))
+                (with-current-buffer (find-file-noselect fsx-file)
+                  (fsharp-load-buffer-file)
+                  (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
+                    (fsi-tests-wait-for-regex 25 "xxx:\\(.*\\):xxx")
+                    (let ((json-str (match-string-no-properties 1)))
+                      (unless json-str
+                        (warn "FSI output doesn't contain marker: %s" (buffer-substring-no-properties (point-min) (point-max))))
+                      (expect json-str :to-equal "{\"X\":2,\"Y\":\"Hello\"}")))))))
+
+(provide 'fsi-tests)
+;;; fsi-tests.el ends here

From b13e983ac437f1664c9ee438c601da8660c8c27c Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 24 Jun 2022 22:39:29 +0200
Subject: [PATCH 115/147] Use pty for inferior F# process

Ensures line-buffering of inferior F# output.

Refs #293
---
 inf-fsharp-mode.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/inf-fsharp-mode.el b/inf-fsharp-mode.el
index 7db9a09..8843bfe 100644
--- a/inf-fsharp-mode.el
+++ b/inf-fsharp-mode.el
@@ -100,7 +100,7 @@ If FILE is not a Tramp filename return FILENAME"
           (or cmd (read-from-minibuffer "fsharp toplevel to run: "
                                         inferior-fsharp-program)))
     (let ((cmdlist (inferior-fsharp-args-to-list inferior-fsharp-program))
-          (process-connection-type nil))
+          (process-connection-type 'pty))
       (with-current-buffer (apply (function make-comint)
                                   inferior-fsharp-buffer-subname
                                   (car cmdlist) nil

From a8703bf50333e1c295f212b7ea6959f1a87d3548 Mon Sep 17 00:00:00 2001
From: Shohei YOSHIDA <syohex@gmail.com>
Date: Wed, 29 Jun 2022 16:55:26 +0900
Subject: [PATCH 116/147] Add missing format specifier

---
 eglot-fsharp.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 5a92954..ff872bc 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -138,7 +138,7 @@
 				       "tool" "install" "fsautocomplete"
 				       "--tool-path" default-directory "--version"
 				       version))
-            (error "'dotnet tool install fsautocomplete --tool-path %s --version ' failed" default-directory  version)))
+            (error "'dotnet tool install fsautocomplete --tool-path %s --version %s' failed" default-directory  version)))
       (error
        (let ((stderr (with-temp-buffer
                        (insert-file-contents stderr-file)

From 9b1b807c4d142431406a984d1c207281ccaf447d Mon Sep 17 00:00:00 2001
From: Shohei YOSHIDA <syohex@gmail.com>
Date: Thu, 30 Jun 2022 11:03:09 +0900
Subject: [PATCH 117/147] Fix byte-compile warnings

- specify ':type' attribute for defcustom variables
- escape quotes in docstring
---
 eglot-fsharp.el          | 3 ++-
 fsharp-mode-structure.el | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index ff872bc..6d99285 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -52,7 +52,8 @@
           (string :tag "Version string")))
 
 (defcustom eglot-fsharp-server-verbose nil
-  "If non-nil include debug output in the server logs.")
+  "If non-nil include debug output in the server logs."
+  :type 'boolean)
 
 (defcustom eglot-fsharp-server-runtime
   (if (executable-find "dotnet")
diff --git a/fsharp-mode-structure.el b/fsharp-mode-structure.el
index 674f612..b7664fb 100644
--- a/fsharp-mode-structure.el
+++ b/fsharp-mode-structure.el
@@ -268,7 +268,7 @@ This function preserves point and mark."
 (defun fsharp-in-literal-p (&optional lim)
   "Return non-nil if point is in a Fsharp literal (a comment or
 string). The return value is specifically one of the symbols
-'comment or 'string. Optional argument LIM indicates the
+\\='comment or \\='string. Optional argument LIM indicates the
 beginning of the containing form, i.e. the limit on how far back
 to scan."
   ;; NOTE: Watch out for infinite recursion between this function and

From c8482eaa5c2c2d85652a701f5935576d9402f6d5 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Thu, 30 Jun 2022 21:38:38 +0200
Subject: [PATCH 118/147] Remove support for .NET full framework

fsautocomplete dropped support for the full framework:

fsharp/FsAutoComplete#652
---
 eglot-fsharp.el | 58 +++++--------------------------------------------
 1 file changed, 6 insertions(+), 52 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 6d99285..67b4a43 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -55,21 +55,9 @@
   "If non-nil include debug output in the server logs."
   :type 'boolean)
 
-(defcustom eglot-fsharp-server-runtime
-  (if (executable-find "dotnet")
-      'net-core
-    'net-framework)
-  "The .NET runtime to use."
-  :group 'eglot-fsharp
-  :type '(choice (const :tag "Use .Net Core" net-core)
-                 (const :tag "Use .Net Framework" net-framework)))
-
 (defun eglot-fsharp--path-to-server ()
   "Return FsAutoComplete path."
-  (file-truename (concat eglot-fsharp-server-install-dir
-                         (if (eq eglot-fsharp-server-runtime 'net-core)
-                             (concat "netcore/fsautocomplete" (if (eq system-type 'windows-nt) ".exe" ""))
-                           "netframework/fsautocomplete.exe"))))
+  (file-truename (concat eglot-fsharp-server-install-dir "netcore/fsautocomplete" (if (eq system-type 'windows-nt) ".exe" ""))))
 
 ;; cache to prevent repetitive queries
 (defvar eglot-fsharp--latest-version nil "Latest fsautocomplete.exe version string.")
@@ -94,32 +82,6 @@
 	       (eglot-fsharp--installed-version))
       (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
 
-(defun eglot-fsharp--install-w32 (version)
-  "Download and install the full framework version of F# compiler service at version VERSION in `eglot-fsharp-server-install-dir'."
-  (let* ((url (format "https://github.com/fsharp/FsAutoComplete/releases/download/%s/fsautocomplete.zip"
-                      version))
-	 (exe (eglot-fsharp--path-to-server))
-         (zip (concat (file-name-directory exe) "fsautocomplete.zip"))
-         (gnutls-algorithm-priority
-          (if (and (not gnutls-algorithm-priority)
-                   (boundp 'libgnutls-version)
-                   (>= libgnutls-version 30603)
-                   (version<= emacs-version "26.2"))
-              "NORMAL:-VERS-TLS1.3"
-            gnutls-algorithm-priority))))
-  (unless (eglot-fsharp-current-version-p version)
-    (url-copy-file url zip t)
-    ;; FIXME: Windows (unzip preinstalled?)
-    (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server))))
-      (unless (zerop (call-process "unzip" nil nil nil "-o" zip))
-        (error "Failed to unzip %s" zip))
-      (unless (eq system-type 'windows-nt)
-	(dolist  (file (directory-files-recursively (file-name-directory (eglot-fsharp--path-to-server)) "." t))
-	  (if (file-directory-p file)
-	      (chmod file #o755)
-	    (chmod file #o644)))))
-    (delete-file zip)))
-
 (defun eglot-fsharp--install-core (version)
   "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."
   (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server)))
@@ -153,9 +115,7 @@
   (let* ((version (or version (if (eq eglot-fsharp-server-version 'latest)
 				  (eglot-fsharp--latest-version)
 				eglot-fsharp-server-version))))
-    (if (eq eglot-fsharp-server-runtime 'net-core)
-	(eglot-fsharp--install-core version)
-      (eglot-fsharp--install-w32 version))))
+    (eglot-fsharp--install-core version)))
 
  ;;;###autoload
 (defun eglot-fsharp
@@ -164,16 +124,10 @@
 Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   (when interactive (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
-    (let ((cmd-list (cond ((eq eglot-fsharp-server-runtime 'net-core)
-			   `(,(eglot-fsharp--path-to-server)))
-			  ((eq window-system 'w32)
-			   `("" , (eglot-fsharp--path-to-server)))
-			  (t `("mono" ,(eglot-fsharp--path-to-server)))))
-	  (arg-list (if eglot-fsharp-server-verbose
-			`("--background-service-enabled" "-v")
-            	      `("--background-service-enabled")
-		      )))
-      (cons 'eglot-fsautocomplete (append cmd-list arg-list)))))
+    (cons 'eglot-fsautocomplete (cons (eglot-fsharp--path-to-server)
+                                      (if eglot-fsharp-server-verbose
+			                  `("--background-service-enabled" "-v")
+            	                        `("--background-service-enabled"))))))
 
 
 

From a8fe13b20382135d4ab204466e2f5e02df935ff3 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 1 Jul 2022 21:52:02 +0200
Subject: [PATCH 119/147] FSI tests: Code cleanup

Move inline fsx code from .el to separate .fsx files.
---
 test/expression.fsx |  1 +
 test/fsi-tests.el   | 53 ++++++++++++++++++---------------------------
 test/nuget.fsx      |  6 +++++
 3 files changed, 28 insertions(+), 32 deletions(-)
 create mode 100644 test/expression.fsx
 create mode 100644 test/nuget.fsx

diff --git a/test/expression.fsx b/test/expression.fsx
new file mode 100644
index 0000000..0bcc167
--- /dev/null
+++ b/test/expression.fsx
@@ -0,0 +1 @@
+1 + 1;;
diff --git a/test/fsi-tests.el b/test/fsi-tests.el
index c0b56ec..ae38069 100644
--- a/test/fsi-tests.el
+++ b/test/fsi-tests.el
@@ -36,38 +36,27 @@
 
 
 (describe "F# interactive"
-          :before-all (run-fsharp inferior-fsharp-program)
-          :before-each (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
-                         (comint-clear-buffer))
-          (it "can eval expressions"
-              (let ((fsharp-autosave-on-file-load t)
-                    (fsx-file (make-temp-file "fsi" nil ".fsx" "
-1 + 1;;
-")))
-                (with-current-buffer (find-file-noselect fsx-file)
-                  (fsharp-eval-region (point-min) (point-max))
-                  (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
-                    (fsi-tests-wait-for-regex 25 "it: int = 2$")
-                    (let ((result (match-string-no-properties 0)))
-                      (expect result :to-equal "it: int = 2"))))))
-          (it "can load nuget references"
-              (let ((fsharp-autosave-on-file-load t)
-                    (timeout 50)
-                    (fsx-file (make-temp-file "fsi" nil ".fsx" "
-#r \"nuget: Newtonsoft.Json\";;
-open Newtonsoft.Json;;
-
-let o = {| X = 2; Y = \"Hello\" |};;
-
-printfn \"xxx:%s:xxx\" (JsonConvert.SerializeObject o);;")))
-                (with-current-buffer (find-file-noselect fsx-file)
-                  (fsharp-load-buffer-file)
-                  (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
-                    (fsi-tests-wait-for-regex 25 "xxx:\\(.*\\):xxx")
-                    (let ((json-str (match-string-no-properties 1)))
-                      (unless json-str
-                        (warn "FSI output doesn't contain marker: %s" (buffer-substring-no-properties (point-min) (point-max))))
-                      (expect json-str :to-equal "{\"X\":2,\"Y\":\"Hello\"}")))))))
+  :before-all (run-fsharp inferior-fsharp-program)
+  :before-each (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
+                 (comint-clear-buffer))
+  (it "can eval expressions"
+    (with-current-buffer (find-file-noselect "test/expression.fsx")
+      (fsharp-eval-region (point-min) (point-max))
+      (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
+        (fsi-tests-wait-for-regex 25 "it: int = 2$")
+        (let ((result (match-string-no-properties 0)))
+          (expect result :to-equal "it: int = 2")))))
+  (it "can load nuget references"
+    (let ((timeout 50)
+          (fsx-file "test/nuget.fsx"))
+      (with-current-buffer (find-file-noselect fsx-file)
+        (fsharp-load-buffer-file)
+        (with-current-buffer (get-buffer inferior-fsharp-buffer-name)
+          (fsi-tests-wait-for-regex 25 "xxx:\\(.*\\):xxx")
+          (let ((json-str (match-string-no-properties 1)))
+            (unless json-str
+              (warn "FSI output doesn't contain marker: %s" (buffer-substring-no-properties (point-min) (point-max))))
+            (expect json-str :to-equal "{\"X\":2,\"Y\":\"Hello\"}")))))))
 
 (provide 'fsi-tests)
 ;;; fsi-tests.el ends here
diff --git a/test/nuget.fsx b/test/nuget.fsx
new file mode 100644
index 0000000..4c32d7f
--- /dev/null
+++ b/test/nuget.fsx
@@ -0,0 +1,6 @@
+#r "nuget: Newtonsoft.Json";;
+open Newtonsoft.Json;;
+
+let o = {| X = 2; Y = "Hello" |};;
+
+printfn "xxx:%s:xxx" (JsonConvert.SerializeObject o);;

From c8bb586621a230a83e292c419624d3a6b1faee91 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 1 Jul 2022 22:15:31 +0200
Subject: [PATCH 120/147] fsi-tests: Fix invalid timeout implemtation

---
 test/fsi-tests.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/fsi-tests.el b/test/fsi-tests.el
index ae38069..3da1a65 100644
--- a/test/fsi-tests.el
+++ b/test/fsi-tests.el
@@ -31,7 +31,7 @@
 (defun fsi-tests-wait-for-regex (timeout regexp)
   (while (and (> timeout 0) (not (progn (goto-char (point-min)) (search-forward-regexp regexp nil t))))
     (message "[FSI Interactive] Waiting a bit...")
-    (accept-process-output (get-buffer-process (current-buffer)) 0.2)
+    (accept-process-output (get-buffer-process (current-buffer)) 0.2 nil t)
     (setq timeout (1- timeout))))
 
 

From 84f736990d11b76c4636b7e1edc4c1e53db26d45 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Fri, 1 Jul 2022 22:23:25 +0200
Subject: [PATCH 121/147] Tests: Fix invalid fsi-tests-wait-for-regex timeout
 implementation

---
 test/fsi-tests.el | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/test/fsi-tests.el b/test/fsi-tests.el
index 3da1a65..450e07f 100644
--- a/test/fsi-tests.el
+++ b/test/fsi-tests.el
@@ -29,10 +29,12 @@
 (require 'fsharp-mode)
 
 (defun fsi-tests-wait-for-regex (timeout regexp)
-  (while (and (> timeout 0) (not (progn (goto-char (point-min)) (search-forward-regexp regexp nil t))))
-    (message "[FSI Interactive] Waiting a bit...")
-    (accept-process-output (get-buffer-process (current-buffer)) 0.2 nil t)
-    (setq timeout (1- timeout))))
+  (let ((start-time (float-time)))
+    (while (and (< (- (float-time) start-time) timeout)
+                (not (progn (goto-char (point-min)) (search-forward-regexp regexp nil t))))
+      (if (accept-process-output (get-buffer-process (current-buffer)) 0.2)
+          (message "[FSI Interactive] received output...")
+        (message "[FSI Interactive] waiting for output...")))))
 
 
 (describe "F# interactive"

From cb5a3420117f581b141176654526ad2df603ec4b Mon Sep 17 00:00:00 2001
From: Andrew McGuier <andrew@echogatetech.com>
Date: Tue, 25 Oct 2022 14:53:07 -0400
Subject: [PATCH 122/147] Update console app parameters

`--background-service` has been deprecated, switch to experimental
adaptive lsp service

change the `-v` parameter to `--verbose` to align with the documentation
---
 eglot-fsharp.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 67b4a43..384fa25 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -126,8 +126,8 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (cons 'eglot-fsautocomplete (cons (eglot-fsharp--path-to-server)
                                       (if eglot-fsharp-server-verbose
-			                  `("--background-service-enabled" "-v")
-            	                        `("--background-service-enabled"))))))
+			                  `("--verbose" "--adaptive-lsp-server-enabled")
+            	                        `("--adaptive-lsp-server-enabled"))))))
 
 
 

From f8873096d24cac7b30419854347220f37345e780 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Thu, 27 Oct 2022 21:23:38 +0200
Subject: [PATCH 123/147] Add `eglot-fsharp-server-args' for additional
 arguments

Make ("--adaptive-lsp-server-enabled") the default args because the
server crashes on boot without the adaptive flag.

Remove `eglot-fsharp-server-verbose'.
---
 eglot-fsharp.el | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 384fa25..d4ea66a 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -51,9 +51,9 @@
           (const :tag "Latest release" latest)
           (string :tag "Version string")))
 
-(defcustom eglot-fsharp-server-verbose nil
-  "If non-nil include debug output in the server logs."
-  :type 'boolean)
+(defcustom eglot-fsharp-server-args '("--adaptive-lsp-server-enabled")
+  "Arguments for the fsautocomplete command when using `eglot-fsharp'."
+  :type '(repeat string))
 
 (defun eglot-fsharp--path-to-server ()
   "Return FsAutoComplete path."
@@ -125,11 +125,7 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   (when interactive (eglot-fsharp--maybe-install))
   (when (file-exists-p (eglot-fsharp--path-to-server))
     (cons 'eglot-fsautocomplete (cons (eglot-fsharp--path-to-server)
-                                      (if eglot-fsharp-server-verbose
-			                  `("--verbose" "--adaptive-lsp-server-enabled")
-            	                        `("--adaptive-lsp-server-enabled"))))))
-
-
+                                      eglot-fsharp-server-args))))
 
 
 (defclass eglot-fsautocomplete (eglot-lsp-server) ()

From 80f4d3a0341c35cb52ea7cc8eb531514240dedf8 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Sun, 6 Nov 2022 21:43:27 +0100
Subject: [PATCH 124/147] Remove "echo" caused by pty-mode inferior fsharp
 process

Refs #311
---
 inf-fsharp-mode.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/inf-fsharp-mode.el b/inf-fsharp-mode.el
index 8843bfe..fbfb05d 100644
--- a/inf-fsharp-mode.el
+++ b/inf-fsharp-mode.el
@@ -73,7 +73,7 @@ be sent from another buffer in fsharp mode.
   (set (make-local-variable 'comment-column) 40)
   (set (make-local-variable 'comment-start-skip) "(\\*+ *")
   (set (make-local-variable 'parse-sexp-ignore-comments) nil)
-  (set (make-local-variable 'comint-process-echoes) nil)
+  (set (make-local-variable 'comint-process-echoes) t)
   (run-hooks 'inferior-fsharp-mode-hooks)
 
   ;; use compilation mode to parse errors, but RET and C-cC-c should still be from comint-mode

From 842174faf791e1a12fbd13863c94e37744feab44 Mon Sep 17 00:00:00 2001
From: Andrew McGuier <andrew@echogatetech.com>
Date: Thu, 25 Aug 2022 01:15:23 -0400
Subject: [PATCH 125/147] Additional FSautocomplete init parameters

---
 eglot-fsharp.el | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index d4ea66a..3b7de45 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -133,7 +133,21 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
 
 (cl-defmethod eglot-initialization-options ((_server eglot-fsautocomplete))
   "Passes through required FsAutoComplete initialization options."
-  '(:automaticWorkspaceInit t))
+  '(
+    :automaticWorkspaceInit t
+    :keywordsAutocomplete t
+    :externalAutocomplete nil
+    :linter t
+    :unionCaseStubGeneration t
+    :recordStubGeneration t
+    :interfaceStubGeneration t
+    :interfaceStubGenerationObjectIdentifier "this"
+    :unusedOpensAnalyzer t
+    :unusedDeclarationsAnalyzer t
+    :useSdkScripts t
+    :simplifyNameAnalyzer nil
+    :resolveNamespaces t
+    :enableReferenceCodeLens t))
 
 ;; FIXME: this should be fixed in FsAutocomplete
 (cl-defmethod xref-backend-definitions :around ((_type symbol) _identifier)

From f631cae3943a31eb0d76acfa160366823234c8d3 Mon Sep 17 00:00:00 2001
From: Andrew McGuier <andrew@echogatetech.com>
Date: Fri, 3 Feb 2023 15:15:37 -0500
Subject: [PATCH 126/147] Add customizable variable for fsautocomplete
 parameters

---
 README.org      |  4 ++--
 eglot-fsharp.el | 36 +++++++++++++++++++++---------------
 2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/README.org b/README.org
index 4983d8b..9d6c0bb 100644
--- a/README.org
+++ b/README.org
@@ -183,8 +183,8 @@ This project is maintained by the
 [[http://fsharp.org/][F# Software Foundation]], with the repository hosted
 on [[https://github.com/fsharp/emacs-fsharp-mode][GitHub]].
 
-Pull requests are welcome. Please run the test-suite with =make
-test= before submitting a pull request.
+Pull requests are welcome. Please run the test-suite with [Eldev](https://doublep.github.io/eldev/) =eldev -dtT test=
+before submitting a pull request.
 
 *** Maintainers
 
diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 3b7de45..f15ac9f 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -55,6 +55,26 @@
   "Arguments for the fsautocomplete command when using `eglot-fsharp'."
   :type '(repeat string))
 
+(defcustom eglot-fsharp-fsautocomplete-args '(
+    :automaticWorkspaceInit t
+    :keywordsAutocomplete t
+    :externalAutocomplete nil
+    :linter t
+    :unionCaseStubGeneration t
+    :recordStubGeneration t
+    :interfaceStubGeneration t
+    :interfaceStubGenerationObjectIdentifier "this"
+    :unusedOpensAnalyzer t
+    :unusedDeclarationsAnalyzer t
+    :useSdkScripts t
+    :simplifyNameAnalyzer nil
+    :resolveNamespaces t
+    :enableReferenceCodeLens t)
+    "Arguments for the fsautocomplete initialization."
+    :group 'eglot-fsharp
+    :risky t
+  )
+
 (defun eglot-fsharp--path-to-server ()
   "Return FsAutoComplete path."
   (file-truename (concat eglot-fsharp-server-install-dir "netcore/fsautocomplete" (if (eq system-type 'windows-nt) ".exe" ""))))
@@ -133,21 +153,7 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
 
 (cl-defmethod eglot-initialization-options ((_server eglot-fsautocomplete))
   "Passes through required FsAutoComplete initialization options."
-  '(
-    :automaticWorkspaceInit t
-    :keywordsAutocomplete t
-    :externalAutocomplete nil
-    :linter t
-    :unionCaseStubGeneration t
-    :recordStubGeneration t
-    :interfaceStubGeneration t
-    :interfaceStubGenerationObjectIdentifier "this"
-    :unusedOpensAnalyzer t
-    :unusedDeclarationsAnalyzer t
-    :useSdkScripts t
-    :simplifyNameAnalyzer nil
-    :resolveNamespaces t
-    :enableReferenceCodeLens t))
+  `(:fSharp ,eglot-fsharp-fsautocomplete-args))
 
 ;; FIXME: this should be fixed in FsAutocomplete
 (cl-defmethod xref-backend-definitions :around ((_type symbol) _identifier)

From 186052e07a6d0e3d20f4fd53c59b081d330c60c4 Mon Sep 17 00:00:00 2001
From: Andrew McGuier <andrew@echogatetech.com>
Date: Fri, 3 Feb 2023 17:24:59 -0500
Subject: [PATCH 127/147] Updating test matrix

---
 .github/workflows/test.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ee6c908..f10cef1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -14,9 +14,9 @@ jobs:
         os: [ubuntu-latest, macos-latest]
         dotnet: [6.0.200]
         emacs_version:
-          - 27.1
           - 27.2
           - 28.1
+          - 28.2
           - snapshot
     steps:
     - uses: purcell/setup-emacs@master

From d087e4efa48a10c7635edcfef0a215c0fb5357e1 Mon Sep 17 00:00:00 2001
From: Andrew McGuier <andrew@echogatetech.com>
Date: Fri, 3 Feb 2023 17:41:23 -0500
Subject: [PATCH 128/147] increase notification timeout

---
 test/eglot-fsharp-integration-util.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/eglot-fsharp-integration-util.el b/test/eglot-fsharp-integration-util.el
index 2dca357..ed27f81 100644
--- a/test/eglot-fsharp-integration-util.el
+++ b/test/eglot-fsharp-integration-util.el
@@ -147,7 +147,7 @@ Pass TIMEOUT to `eglot--with-timeout'."
 
 (defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
   (eglot-fsharp--sniffing (:server-notifications s-notifs)
-                          (eglot-fsharp--wait-for (s-notifs 20)
+                          (eglot-fsharp--wait-for (s-notifs 30)
                                            (&key _id method params &allow-other-keys)
                                            (and
                                             (string= method "textDocument/publishDiagnostics")
@@ -155,7 +155,7 @@ Pass TIMEOUT to `eglot--with-timeout'."
 
 (defun eglot-fsharp--sniff-method (method-name)
   (eglot-fsharp--sniffing (:server-notifications s-notifs)
-                          (eglot-fsharp--wait-for (s-notifs 20)
+                          (eglot-fsharp--wait-for (s-notifs 30)
                                            (&key _id method params &allow-other-keys)
                                            (and
                                             (string= method method-name)))))

From ff035ca17b603da895242cd77853b7c22befbc8c Mon Sep 17 00:00:00 2001
From: Andrew McGuier <andrew@echogatetech.com>
Date: Fri, 3 Feb 2023 18:10:03 -0500
Subject: [PATCH 129/147] sniff signal before trigger the text change.

There's a potential race condition where the diagnostic message
arrives before the signal sniffing is attached.
---
 test/eglot-fsharp-integration-util.el | 4 ++--
 test/integration-tests.el             | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/test/eglot-fsharp-integration-util.el b/test/eglot-fsharp-integration-util.el
index ed27f81..2dca357 100644
--- a/test/eglot-fsharp-integration-util.el
+++ b/test/eglot-fsharp-integration-util.el
@@ -147,7 +147,7 @@ Pass TIMEOUT to `eglot--with-timeout'."
 
 (defun eglot-fsharp--sniff-diagnostics (file-name-suffix)
   (eglot-fsharp--sniffing (:server-notifications s-notifs)
-                          (eglot-fsharp--wait-for (s-notifs 30)
+                          (eglot-fsharp--wait-for (s-notifs 20)
                                            (&key _id method params &allow-other-keys)
                                            (and
                                             (string= method "textDocument/publishDiagnostics")
@@ -155,7 +155,7 @@ Pass TIMEOUT to `eglot--with-timeout'."
 
 (defun eglot-fsharp--sniff-method (method-name)
   (eglot-fsharp--sniffing (:server-notifications s-notifs)
-                          (eglot-fsharp--wait-for (s-notifs 30)
+                          (eglot-fsharp--wait-for (s-notifs 20)
                                            (&key _id method params &allow-other-keys)
                                            (and
                                             (string= method method-name)))))
diff --git a/test/integration-tests.el b/test/integration-tests.el
index 02a95a4..9e66957 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -61,11 +61,11 @@
     (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Error.fs")
       (flymake-mode t)
       (flymake-start)
+      (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
       (goto-char (point-min))
       (search-forward "nonexisting")
       (insert "x")
       (eglot--signal-textDocument/didChange)
-      (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
       (flymake-goto-next-error 1 '() t)
       (expect (face-at-point) :to-be 'flymake-error )))
   (it "provides completion"

From ceafc404df945d86c41099a057232cd5a248c5a9 Mon Sep 17 00:00:00 2001
From: August Feng <augustfengd@gmail.com>
Date: Sun, 11 Dec 2022 22:46:22 -0500
Subject: [PATCH 130/147] disable self run mode hooks and let emacs run it

If we run the hook ourselves, we could cause unexpected behaviours in case an
external entity also adds hooks to the major mode.
---
 fsharp-mode.el | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index 8d25a25..eab2f66 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -241,9 +241,7 @@ If set to t, the buffer will always be saved, silently."
 
   (let ((file (buffer-file-name)))
     (when file
-      (setq compile-command (fsharp-mode-choose-compile-command file))))
-
-  (run-hooks 'fsharp-mode-hook))
+      (setq compile-command (fsharp-mode-choose-compile-command file)))))
 
 (defun fsharp-mode-choose-compile-command (file)
   "Format an appropriate compilation command, depending on several factors:

From 8a1501764317d3414f2d97d7679504910600e934 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 19 Feb 2023 15:58:22 +0100
Subject: [PATCH 131/147] Code cleanup

---
 fsharp-mode.el | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index eab2f66..4305bd7 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -239,9 +239,8 @@ If set to t, the buffer will always be saved, silently."
   ;; has no deterministic indentation.
   (when (boundp 'electric-indent-inhibit) (setq electric-indent-inhibit t))
 
-  (let ((file (buffer-file-name)))
-    (when file
-      (setq compile-command (fsharp-mode-choose-compile-command file)))))
+  (when-let ((file (buffer-file-name)))
+    (setq compile-command (fsharp-mode-choose-compile-command file))))
 
 (defun fsharp-mode-choose-compile-command (file)
   "Format an appropriate compilation command, depending on several factors:

From 7623e1d6e93b5d3b647ab3a58969d68cf2a2a3a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 19 Feb 2023 16:04:10 +0100
Subject: [PATCH 132/147] Update copyright year

---
 eglot-fsharp.el                       | 2 +-
 fsharp-mode.el                        | 2 +-
 test/eglot-fsharp-integration-util.el | 2 +-
 test/fsi-tests.el                     | 2 +-
 test/integration-tests.el             | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index f15ac9f..1e89103 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -1,6 +1,6 @@
 ;;; eglot-fsharp.el --- fsharp-mode eglot integration                     -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019-2022  Jürgen Hötzel
+;; Copyright (C) 2019-2023  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Package-Requires: ((emacs "27.1") (eglot "1.4") (fsharp-mode "1.10") (jsonrpc "1.0.14"))
diff --git a/fsharp-mode.el b/fsharp-mode.el
index 4305bd7..c8720ab 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -5,7 +5,7 @@
 ;; Author: 1993-1997 Xavier Leroy, Jacques Garrigue and Ian T Zimmerman
 ;;         2010-2011 Laurent Le Brun <laurent@le-brun.eu>
 ;;         2012-2014 Robin Neatherway <robin.neatherway@gmail.com>
-;;         2017-2022 Jürgen Hötzel
+;;         2017-2023 Jürgen Hötzel
 ;; Maintainer: Jürgen Hötzel
 ;; Package-Requires: ((emacs "25"))
 ;; Keywords: languages
diff --git a/test/eglot-fsharp-integration-util.el b/test/eglot-fsharp-integration-util.el
index 2dca357..c1fbf83 100644
--- a/test/eglot-fsharp-integration-util.el
+++ b/test/eglot-fsharp-integration-util.el
@@ -1,6 +1,6 @@
 ;;; eglot-fsharp-integration-util.el --- Helper for eglot integration tests  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2022  Jürgen Hötzel
+;; Copyright (C) 2022-2023  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Keywords: processes
diff --git a/test/fsi-tests.el b/test/fsi-tests.el
index 450e07f..4b22d18 100644
--- a/test/fsi-tests.el
+++ b/test/fsi-tests.el
@@ -1,6 +1,6 @@
 ;;; fsi-tests.el --- Tests for F# interactive        -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2022  Jürgen Hötzel
+;; Copyright (C) 2022-2023  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Keywords: processes
diff --git a/test/integration-tests.el b/test/integration-tests.el
index 9e66957..52fb570 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -1,6 +1,6 @@
 ;;; integration-tests.el ---                         -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019-2022  Jürgen Hötzel
+;; Copyright (C) 2019-2023  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Keywords: abbrev, abbrev

From 6e3c9186ac2f136c3a1cfce898e9deb2482b286e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20H=C3=B6tzel?= <juergen@hoetzel.info>
Date: Sun, 19 Mar 2023 19:52:01 +0100
Subject: [PATCH 133/147] Make `eglot-fsharp' tramp aware

Install "fsautocomplete" on the remote host if `default-directory' is
a tramp filename.

Add pipe-workaround for remote fsautocomplete processes: There seems
to be a problem related to CRLF coded input in remote fsautocomplete
processes. Wrapping the process using a cat pipe fixes the
issue.

Even when setting `process-connection-type' to nil or 'pipe there is
still a pseudo tty for the started remote process:
https://www.gnu.org/software/emacs/manual/html_node/tramp/Remote-processes.html#Remote-process-connection-type

Fixes #324
---
 eglot-fsharp.el | 52 +++++++++++++++++++++++++++----------------------
 1 file changed, 29 insertions(+), 23 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 1e89103..5438f5b 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -91,35 +91,38 @@
 
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."
-  (seq-some (lambda (s) (and (string-match "^fsautocomplete[[:space:]]+\\([0-9\.]*\\)[[:space:]]+" s) (match-string 1 s)))
-	    (process-lines "dotnet"  "tool" "list" "--tool-path" (file-name-directory (eglot-fsharp--path-to-server)))))
+  (with-temp-buffer
+    (process-file "dotnet" nil t nil "tool" "list" "--tool-path" (file-name-directory (eglot-fsharp--path-to-server)))
+    (goto-char (point-min))
+    (when (search-forward-regexp "^fsautocomplete[[:space:]]+\\([0-9\.]*\\)[[:space:]]+" nil t)
+      (match-string 1))))
 
 (defun eglot-fsharp-current-version-p (version)
-  "Return t if the installation is not outdated."
-  (when (file-exists-p (eglot-fsharp--path-to-server))
-    (if (eq version 'latest)
-	(equal (eglot-fsharp--latest-version)
-	       (eglot-fsharp--installed-version))
-      (equal eglot-fsharp-server-version (eglot-fsharp--installed-version)))))
+  "Return t if the installation is up-to-date compared to VERSION string."
+  (and (file-exists-p (concat (file-remote-p default-directory) (eglot-fsharp--path-to-server)))
+       (equal version (eglot-fsharp--installed-version))))
 
 (defun eglot-fsharp--install-core (version)
   "Download and install fsautocomplete as a dotnet tool at version VERSION in `eglot-fsharp-server-install-dir'."
-  (let ((default-directory (file-name-directory (eglot-fsharp--path-to-server)))
-        (stderr-file (make-temp-file "dotnet_stderr")))
+  (let* ((default-directory (concat (file-remote-p default-directory)
+                                    (file-name-directory (eglot-fsharp--path-to-server))))
+         (stderr-file (make-temp-file "dotnet_stderr"))
+         (local-tool-path (or (file-remote-p default-directory 'localname) default-directory)))
     (condition-case err
         (progn
           (unless (eglot-fsharp-current-version-p version)
             (message "Installing fsautocomplete version %s" version)
-            (when (file-exists-p (eglot-fsharp--path-to-server))
-	      (unless (zerop (call-process "dotnet" nil `(nil
+            (when (file-exists-p (concat (file-remote-p default-directory)
+                                         (eglot-fsharp--path-to-server)))
+	      (unless (zerop (process-file "dotnet" nil `(nil
 							  ,stderr-file)
 					   nil "tool" "uninstall"
 					   "fsautocomplete" "--tool-path"
-					   default-directory))
+					   local-tool-path))
                 (error  "'dotnet tool uninstall fsautocomplete --tool-path %s' failed" default-directory))))
-          (unless (zerop (call-process "dotnet" nil `(nil ,stderr-file) nil
+          (unless (zerop (process-file "dotnet" nil `(nil ,stderr-file) nil
 				       "tool" "install" "fsautocomplete"
-				       "--tool-path" default-directory "--version"
+				       "--tool-path" local-tool-path "--version"
 				       version))
             (error "'dotnet tool install fsautocomplete --tool-path %s --version %s' failed" default-directory  version)))
       (error
@@ -131,21 +134,24 @@
 
 (defun eglot-fsharp--maybe-install (&optional version)
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
-  (make-directory (file-name-directory (eglot-fsharp--path-to-server)) t)
+  (make-directory (concat (file-remote-p default-directory)
+                          (file-name-directory (eglot-fsharp--path-to-server))) t)
   (let* ((version (or version (if (eq eglot-fsharp-server-version 'latest)
 				  (eglot-fsharp--latest-version)
 				eglot-fsharp-server-version))))
-    (eglot-fsharp--install-core version)))
+    (unless (eglot-fsharp-current-version-p version)
+      (eglot-fsharp--install-core version))))
 
  ;;;###autoload
-(defun eglot-fsharp
-    (interactive)
-  "Return `eglot' contact when FsAutoComplete is installed.
+(defun eglot-fsharp (interactive)
+    "Return `eglot' contact when FsAutoComplete is installed.
 Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   (when interactive (eglot-fsharp--maybe-install))
-  (when (file-exists-p (eglot-fsharp--path-to-server))
-    (cons 'eglot-fsautocomplete (cons (eglot-fsharp--path-to-server)
-                                      eglot-fsharp-server-args))))
+  (cons 'eglot-fsautocomplete
+        (if (file-remote-p default-directory)
+            `("sh" ,shell-command-switch ,(concat "cat|"  (mapconcat #'shell-quote-argument
+                                                                     (cons (eglot-fsharp--path-to-server) eglot-fsharp-server-args) " ")))
+          (cons (eglot-fsharp--path-to-server) eglot-fsharp-server-args))))
 
 
 (defclass eglot-fsautocomplete (eglot-lsp-server) ()

From e221789249f3716a3381f1ce626c705d500545be Mon Sep 17 00:00:00 2001
From: Andrew McGuier <amcguier@pluto.home.arpa>
Date: Fri, 24 Mar 2023 04:22:49 -0400
Subject: [PATCH 134/147] Updating the configuration object to match Ionide
 configuration
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Andrew McGuier <andrew@echogatetech.com>
Co-authored-by: Jürgen Hötzel <juergen@hoetzel.info>
---
 eglot-fsharp.el | 83 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 63 insertions(+), 20 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index 5438f5b..bce6c81 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -56,23 +56,66 @@
   :type '(repeat string))
 
 (defcustom eglot-fsharp-fsautocomplete-args '(
-    :automaticWorkspaceInit t
-    :keywordsAutocomplete t
-    :externalAutocomplete nil
-    :linter t
-    :unionCaseStubGeneration t
-    :recordStubGeneration t
-    :interfaceStubGeneration t
-    :interfaceStubGenerationObjectIdentifier "this"
-    :unusedOpensAnalyzer t
-    :unusedDeclarationsAnalyzer t
-    :useSdkScripts t
-    :simplifyNameAnalyzer nil
-    :resolveNamespaces t
-    :enableReferenceCodeLens t)
-    "Arguments for the fsautocomplete initialization."
-    :group 'eglot-fsharp
-    :risky t
+                                              :automaticWorkspaceInit t
+                                              :abstractClassStubGeneration t
+				              :abstractClassStubGenerationMethodBody
+				              "failwith \"Not Implemented\""
+				              :abstractClassStubGenerationObjectIdentifier "this"
+				              :addFsiWatcher nil
+				              :codeLenses (:references (:enabled t)
+							   :signature (:enabled t))
+				              :disableFailedProjectNotifications nil
+				              :dotnetRoot ""
+				              :enableAdaptiveLspServer t
+				              :enableAnalyzers nil
+				              :enableMSBuildProjectGraph nil
+				              :enableReferenceCodeLens t
+				              :excludeProjectDirectories [".git" "paket-files" ".fable" "packages" "node_modules"]
+				              :externalAutocomplete nil
+				              :fsac (:attachDebugger nil
+                                                                     :cachedTypeCheckCount 200
+				                                     :conserveMemory nil
+				                                     :dotnetArgs nil
+				                                     :netCoreDllPath ""
+				                                     :parallelReferenceResolution nil
+				                                     :silencedLogs nil)
+				              :fsiExtraParameters nil
+				              :fsiSdkFilePath ""
+				              :generateBinlog nil
+				              :indentationSize 4
+				              :inlayHints (:disableLongTooltip nil
+								               :enabled t
+								               :parameterNames t
+								               :typeAnnotations t)
+				              :inlineValues (:enabled nil
+							              :prefix "//")
+				              :interfaceStubGeneration t
+				              :interfaceStubGenerationMethodBody "failwith \"Not Implemented\""
+				              :interfaceStubGenerationObjectIdentifier "this"
+				              :keywordsAutocomplete t
+				              :lineLens (:enabled "replaceCodeLens"
+					                          :prefix " // ")
+				              :linter t
+				              :pipelineHints (:enabled t
+							               :prefix " // ")
+				              :recordStubGeneration t
+				              :recordStubGenerationBody "failwith \"Not Implemented\""
+				              :resolveNamespaces t
+				              :saveOnSendLastSelection nil
+				              :simplifyNameAnalyzer t
+				              :smartIndent nil
+				              :suggestGitignore t
+				              :suggestSdkScripts t
+				              :unionCaseStubGeneration t
+				              :unionCaseStubGenerationBody "failwith \"Not Implemented\""
+				              :unusedDeclarationsAnalyzer t
+				              :unusedOpensAnalyzer t
+				              :verboseLogging nil
+				              :workspaceModePeekDeepLevel 4
+				              :workspacePath "")
+  "Arguments for the fsautocomplete workspace configuration."
+  :group 'eglot-fsharp
+  :risky t
   )
 
 (defun eglot-fsharp--path-to-server ()
@@ -142,9 +185,9 @@
     (unless (eglot-fsharp-current-version-p version)
       (eglot-fsharp--install-core version))))
 
- ;;;###autoload
+;;;###autoload
 (defun eglot-fsharp (interactive)
-    "Return `eglot' contact when FsAutoComplete is installed.
+  "Return `eglot' contact when FsAutoComplete is installed.
 Ensure FsAutoComplete is installed (when called INTERACTIVE)."
   (when interactive (eglot-fsharp--maybe-install))
   (cons 'eglot-fsautocomplete
@@ -159,7 +202,7 @@ Ensure FsAutoComplete is installed (when called INTERACTIVE)."
 
 (cl-defmethod eglot-initialization-options ((_server eglot-fsautocomplete))
   "Passes through required FsAutoComplete initialization options."
-  `(:fSharp ,eglot-fsharp-fsautocomplete-args))
+  eglot-fsharp-fsautocomplete-args)
 
 ;; FIXME: this should be fixed in FsAutocomplete
 (cl-defmethod xref-backend-definitions :around ((_type symbol) _identifier)

From 202277528cc9343ddc882a396978d11d716f9ec0 Mon Sep 17 00:00:00 2001
From: August Feng <augustfengd@gmail.com>
Date: Tue, 20 Jun 2023 15:41:28 -0400
Subject: [PATCH 135/147] Enable nxml-mode for fsproj files

---
 fsharp-mode.el | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index c8720ab..41199e6 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -114,6 +114,7 @@
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.fs[iylx]?\\'" . fsharp-mode))
+(add-to-list 'auto-mode-alist '("\\.fsproj\\'" . nxml-mode))
 
 (defvar fsharp-mode-syntax-table nil
   "Syntax table in use in fsharp mode buffers.")

From 993ffee2e714eba4d39529b7b7d5ee9c2541f02d Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 14 May 2024 17:38:25 +0200
Subject: [PATCH 136/147] Allow to use "fsautocomplete" from the global
 tool-path.

Setting `eglot-fsharp-server-install-dir' to nil disables the custom
"~/.emacs.d/FsAutoComplete/netcore/" tool path.

Fixes #341
---
 eglot-fsharp.el | 51 +++++++++++++++++++++++++++----------------------
 1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index bce6c81..bcb820e 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -1,6 +1,6 @@
 ;;; eglot-fsharp.el --- fsharp-mode eglot integration                     -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2019-2023  Jürgen Hötzel
+;; Copyright (C) 2019-2024  Jürgen Hötzel
 
 ;; Author: Jürgen Hötzel <juergen@hoetzel.info>
 ;; Package-Requires: ((emacs "27.1") (eglot "1.4") (fsharp-mode "1.10") (jsonrpc "1.0.14"))
@@ -41,7 +41,7 @@
   "Install directory for FsAutoComplete."
   :group 'eglot-fsharp
   :risky t
-  :type 'directory)
+  :type '(choice directory (const :tag "Use dotnet default for tool-path" nil)))
 
 (defcustom eglot-fsharp-server-version 'latest
   "FsAutoComplete version to install or update."
@@ -63,7 +63,7 @@
 				              :abstractClassStubGenerationObjectIdentifier "this"
 				              :addFsiWatcher nil
 				              :codeLenses (:references (:enabled t)
-							   :signature (:enabled t))
+							               :signature (:enabled t))
 				              :disableFailedProjectNotifications nil
 				              :dotnetRoot ""
 				              :enableAdaptiveLspServer t
@@ -120,7 +120,10 @@
 
 (defun eglot-fsharp--path-to-server ()
   "Return FsAutoComplete path."
-  (file-truename (concat eglot-fsharp-server-install-dir "netcore/fsautocomplete" (if (eq system-type 'windows-nt) ".exe" ""))))
+  (let ((base (if eglot-fsharp-server-install-dir
+                  (concat eglot-fsharp-server-install-dir "netcore/")
+                "~/.dotnet/tools/")))
+    (expand-file-name (concat base "fsautocomplete" (if (eq system-type 'windows-nt) ".exe" "")))))
 
 ;; cache to prevent repetitive queries
 (defvar eglot-fsharp--latest-version nil "Latest fsautocomplete.exe version string.")
@@ -135,7 +138,9 @@
 (defun eglot-fsharp--installed-version ()
   "Return version string of fsautocomplete."
   (with-temp-buffer
-    (process-file "dotnet" nil t nil "tool" "list" "--tool-path" (file-name-directory (eglot-fsharp--path-to-server)))
+    (if eglot-fsharp-server-install-dir
+        (process-file "dotnet" nil t nil "tool" "list" "--tool-path" (file-name-directory (eglot-fsharp--path-to-server)))
+      (process-file "dotnet" nil t nil "tool" "list" "-g"))
     (goto-char (point-min))
     (when (search-forward-regexp "^fsautocomplete[[:space:]]+\\([0-9\.]*\\)[[:space:]]+" nil t)
       (match-string 1))))
@@ -150,35 +155,35 @@
   (let* ((default-directory (concat (file-remote-p default-directory)
                                     (file-name-directory (eglot-fsharp--path-to-server))))
          (stderr-file (make-temp-file "dotnet_stderr"))
-         (local-tool-path (or (file-remote-p default-directory 'localname) default-directory)))
+         (local-tool-path (or (file-remote-p default-directory 'localname) default-directory))
+         (process-file-uninstall-args (if eglot-fsharp-server-install-dir
+                                          (list "dotnet" nil `(nil ,stderr-file) nil "tool" "uninstall" "fsautocomplete" "--tool-path" local-tool-path)
+                                        (list "dotnet" nil `(nil ,stderr-file) nil "tool" "uninstall" "-g" "fsautocomplete")))
+         (process-file-install-args (if eglot-fsharp-server-install-dir
+                                        (list "dotnet" nil `(nil ,stderr-file) nil "tool" "install" "fsautocomplete" "--tool-path" local-tool-path "--version" version)
+                                      (list "dotnet" nil `(nil ,stderr-file) nil "tool" "install" "fsautocomplete" "-g" "--version" version))))
+    (make-directory default-directory t)
     (condition-case err
         (progn
-          (unless (eglot-fsharp-current-version-p version)
-            (message "Installing fsautocomplete version %s" version)
-            (when (file-exists-p (concat (file-remote-p default-directory)
-                                         (eglot-fsharp--path-to-server)))
-	      (unless (zerop (process-file "dotnet" nil `(nil
-							  ,stderr-file)
-					   nil "tool" "uninstall"
-					   "fsautocomplete" "--tool-path"
-					   local-tool-path))
-                (error  "'dotnet tool uninstall fsautocomplete --tool-path %s' failed" default-directory))))
-          (unless (zerop (process-file "dotnet" nil `(nil ,stderr-file) nil
-				       "tool" "install" "fsautocomplete"
-				       "--tool-path" local-tool-path "--version"
-				       version))
+          (unless (or (eglot-fsharp-current-version-p version) (not (eglot-fsharp--installed-version)))
+            (message "Uninstalling fsautocomplete version %s" (eglot-fsharp--installed-version))
+            (unless (zerop (apply #'process-file process-file-uninstall-args))
+              (error  "'dotnet tool uninstall fsautocomplete ... failed")))
+          (unless (zerop (apply #'process-file process-file-install-args))
             (error "'dotnet tool install fsautocomplete --tool-path %s --version %s' failed" default-directory  version)))
       (error
        (let ((stderr (with-temp-buffer
                        (insert-file-contents stderr-file)
                        (buffer-string))))
          (delete-file stderr-file)
-         (signal (car err) (format "%s: %s" (cdr err) stderr)))))))
+         (signal (car err) (format "%s: %s" (cdr err) stderr)))))
+    (message "Installed fsautocomplete to %s" (eglot-fsharp--path-to-server))))
 
 (defun eglot-fsharp--maybe-install (&optional version)
   "Downloads F# compiler service, and install in `eglot-fsharp-server-install-dir'."
-  (make-directory (concat (file-remote-p default-directory)
-                          (file-name-directory (eglot-fsharp--path-to-server))) t)
+  (unless eglot-fsharp-server-install-dir
+    (make-directory (concat (file-remote-p default-directory)
+                            (file-name-directory (eglot-fsharp--path-to-server))) t))
   (let* ((version (or version (if (eq eglot-fsharp-server-version 'latest)
 				  (eglot-fsharp--latest-version)
 				eglot-fsharp-server-version))))

From 65feb1ef5d662af57f268484dbb9f35179190a5a Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 14 May 2024 21:11:19 +0200
Subject: [PATCH 137/147] Increase default test timeout

---
 test/eglot-fsharp-integration-util.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/eglot-fsharp-integration-util.el b/test/eglot-fsharp-integration-util.el
index c1fbf83..7d16f52 100644
--- a/test/eglot-fsharp-integration-util.el
+++ b/test/eglot-fsharp-integration-util.el
@@ -62,7 +62,7 @@
   (find-file-noselect file))
 
 (defun eglot-fsharp--tests-connect (&optional timeout)
-  (let* ((timeout (or timeout 10))
+  (let* ((timeout (or timeout 30))
          (eglot-sync-connect t)
          (eglot-connect-timeout timeout))
     (apply #'eglot--connect (eglot--guess-contact))))

From cfc7047fc1acec702de0c10cad12ab89a972230a Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 14 May 2024 21:16:41 +0200
Subject: [PATCH 138/147] Tests: Update dotnet version / Add new Emacs release

---
 .github/workflows/test.yml | 90 +++++++++++++++++++-------------------
 1 file changed, 45 insertions(+), 45 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f10cef1..20fc682 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -12,58 +12,58 @@ jobs:
       fail-fast: false
       matrix:
         os: [ubuntu-latest, macos-latest]
-        dotnet: [6.0.200]
+        dotnet: [8.0.x]
         emacs_version:
           - 27.2
-          - 28.1
           - 28.2
+          - 29.3
           - snapshot
     steps:
-    - uses: purcell/setup-emacs@master
-      with:
-        version: ${{ matrix.emacs_version }}
-    - uses: actions/setup-dotnet@v1
-      with:
-        dotnet-version: ${{ matrix.dotnet }}
-    - uses: actions/checkout@v2
-    - name: Install Eldev
-      run: curl -fsSL https://raw.github.com/doublep/eldev/master/webinstall/github-eldev | sh
-    - name: Show dotnet sdks
-      run: dotnet --list-sdks
-    - name: Show dotnet version
-      run: dotnet --info
-    - name: Test
-      run: |
-        echo "Archives:"
-        eldev archives
-        echo "Dependencies:"
-        eldev -v dependencies
-        echo "Testing:"
-        eldev -dtT test
+      - uses: purcell/setup-emacs@master
+        with:
+          version: ${{ matrix.emacs_version }}
+      - uses: actions/setup-dotnet@v1
+        with:
+          dotnet-version: ${{ matrix.dotnet }}
+      - uses: actions/checkout@v2
+      - name: Install Eldev
+        run: curl -fsSL https://raw.github.com/doublep/eldev/master/webinstall/github-eldev | sh
+      - name: Show dotnet sdks
+        run: dotnet --list-sdks
+      - name: Show dotnet version
+        run: dotnet --info
+      - name: Test
+        run: |
+          echo "Archives:"
+          eldev archives
+          echo "Dependencies:"
+          eldev -v dependencies
+          echo "Testing:"
+          eldev -dtT test
   windows-build:
     runs-on: windows-latest
     strategy:
       fail-fast: false
     steps:
-    - uses: actions/setup-dotnet@v1
-      with:
-        dotnet-version: 6.0.200
-    - name: Show dotnet sdks
-      run: dotnet --list-sdks
-    - name: Show dotnet version
-      run: dotnet --info
-    - name: Set up Emacs on Windows
-      uses: jcs090218/setup-emacs-windows@master
-      with:
-        version: 28.1
-    - uses: actions/checkout@v2
-    - name: Install Eldev
-      run: curl.exe -fsSL https://raw.github.com/doublep/eldev/master/webinstall/eldev.bat | cmd /Q
-    - name: Test
-      run: |
-        echo "Archives:"
-        ~/.local/bin/eldev.bat archives
-        echo "Dependencies:"
-        ~/.local/bin/eldev.bat dependencies
-        echo "Testing:"
-        ~/.local/bin/eldev.bat -p -dtT test
+      - uses: actions/setup-dotnet@v1
+        with:
+          dotnet-version: 6.0.200
+      - name: Show dotnet sdks
+        run: dotnet --list-sdks
+      - name: Show dotnet version
+        run: dotnet --info
+      - name: Set up Emacs on Windows
+        uses: jcs090218/setup-emacs-windows@master
+        with:
+          version: 28.1
+      - uses: actions/checkout@v2
+      - name: Install Eldev
+        run: curl.exe -fsSL https://raw.github.com/doublep/eldev/master/webinstall/eldev.bat | cmd /Q
+      - name: Test
+        run: |
+          echo "Archives:"
+          ~/.local/bin/eldev.bat archives
+          echo "Dependencies:"
+          ~/.local/bin/eldev.bat dependencies
+          echo "Testing:"
+          ~/.local/bin/eldev.bat -p -dtT test

From fe8037f354eaa4ab29923be6d434d178edf71fc2 Mon Sep 17 00:00:00 2001
From: DEADBLACKCLOVER <deadblackclover@protonmail.com>
Date: Sun, 22 Dec 2024 12:30:19 +0700
Subject: [PATCH 139/147] Added eglot-fsharp-server-path

---
 eglot-fsharp.el | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/eglot-fsharp.el b/eglot-fsharp.el
index bcb820e..1ca7940 100644
--- a/eglot-fsharp.el
+++ b/eglot-fsharp.el
@@ -36,6 +36,11 @@
   :link '(url-link "https://github.com/fsharp/FsAutoComplete")
   :group 'eglot)
 
+(defcustom eglot-fsharp-server-path "~/.dotnet/tools/"
+  "Path to the location of FsAutoComplete."
+  :group 'eglot-fsharp
+  :risky t)
+
 (defcustom eglot-fsharp-server-install-dir
   (locate-user-emacs-file "FsAutoComplete/")
   "Install directory for FsAutoComplete."
@@ -122,7 +127,7 @@
   "Return FsAutoComplete path."
   (let ((base (if eglot-fsharp-server-install-dir
                   (concat eglot-fsharp-server-install-dir "netcore/")
-                "~/.dotnet/tools/")))
+                eglot-fsharp-server-path)))
     (expand-file-name (concat base "fsautocomplete" (if (eq system-type 'windows-nt) ".exe" "")))))
 
 ;; cache to prevent repetitive queries

From dac487f6be752a94910b64e2d0d94445a0cac00d Mon Sep 17 00:00:00 2001
From: 64J0 <vinigaio97@gmail.com>
Date: Fri, 7 Feb 2025 17:15:13 -0300
Subject: [PATCH 140/147] update tests on ci by:

- using new action versions
- using .NET 9
- improving test structure to make it easier to understand which step is failing

and comment automated tests code that are currently failing (must be fixed in another PR)
---
 .github/workflows/test.yml            | 37 ++++++++++++++++-----------
 test/Test1/Test1.fsproj               |  2 +-
 test/eglot-fsharp-integration-util.el |  2 +-
 test/integration-tests.el             | 28 ++++++++++----------
 4 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 20fc682..9e97395 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,52 +2,56 @@ name: "CI"
 on:
   pull_request:
   push:
-    # Comment out this section to enable testing of all branches.
     branches:
       - master
 jobs:
   gnu-build:
-    runs-on: ubuntu-latest
     strategy:
       fail-fast: false
       matrix:
         os: [ubuntu-latest, macos-latest]
-        dotnet: [8.0.x]
+        dotnet: [9.0.x]
         emacs_version:
-          - 27.2
           - 28.2
-          - 29.3
+          - 29.4
           - snapshot
+    runs-on: ${{ matrix.os }}
     steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-dotnet@v4
+        with:
+          dotnet-version: ${{ matrix.dotnet }}
       - uses: purcell/setup-emacs@master
         with:
           version: ${{ matrix.emacs_version }}
-      - uses: actions/setup-dotnet@v1
-        with:
-          dotnet-version: ${{ matrix.dotnet }}
-      - uses: actions/checkout@v2
       - name: Install Eldev
         run: curl -fsSL https://raw.github.com/doublep/eldev/master/webinstall/github-eldev | sh
       - name: Show dotnet sdks
         run: dotnet --list-sdks
       - name: Show dotnet version
         run: dotnet --info
-      - name: Test
+      - name: Eldev archives
         run: |
           echo "Archives:"
           eldev archives
+      - name: Eldev dependencies
+        run: |
           echo "Dependencies:"
           eldev -v dependencies
+      - name: Test
+        run: |
           echo "Testing:"
           eldev -dtT test
+          
   windows-build:
     runs-on: windows-latest
     strategy:
       fail-fast: false
     steps:
-      - uses: actions/setup-dotnet@v1
+      - uses: actions/checkout@v4
+      - uses: actions/setup-dotnet@v4
         with:
-          dotnet-version: 6.0.200
+          dotnet-version: 9.0.x
       - name: Show dotnet sdks
         run: dotnet --list-sdks
       - name: Show dotnet version
@@ -55,15 +59,18 @@ jobs:
       - name: Set up Emacs on Windows
         uses: jcs090218/setup-emacs-windows@master
         with:
-          version: 28.1
-      - uses: actions/checkout@v2
+          version: 29.4
       - name: Install Eldev
         run: curl.exe -fsSL https://raw.github.com/doublep/eldev/master/webinstall/eldev.bat | cmd /Q
-      - name: Test
+      - name: Eldev archives
         run: |
           echo "Archives:"
           ~/.local/bin/eldev.bat archives
+      - name: Eldev dependencies
+        run: |
           echo "Dependencies:"
           ~/.local/bin/eldev.bat dependencies
+      - name: Test
+        run: |
           echo "Testing:"
           ~/.local/bin/eldev.bat -p -dtT test
diff --git a/test/Test1/Test1.fsproj b/test/Test1/Test1.fsproj
index 15ef69f..5cccab9 100644
--- a/test/Test1/Test1.fsproj
+++ b/test/Test1/Test1.fsproj
@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net5.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/test/eglot-fsharp-integration-util.el b/test/eglot-fsharp-integration-util.el
index 7d16f52..c1fbf83 100644
--- a/test/eglot-fsharp-integration-util.el
+++ b/test/eglot-fsharp-integration-util.el
@@ -62,7 +62,7 @@
   (find-file-noselect file))
 
 (defun eglot-fsharp--tests-connect (&optional timeout)
-  (let* ((timeout (or timeout 30))
+  (let* ((timeout (or timeout 10))
          (eglot-sync-connect t)
          (eglot-connect-timeout timeout))
     (apply #'eglot--connect (eglot--guess-contact))))
diff --git a/test/integration-tests.el b/test/integration-tests.el
index 52fb570..65e7e07 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -48,26 +48,28 @@
                      (eglot-fsharp--maybe-install)
                      (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
                        (eglot-fsharp--tests-connect 10)
-                       (eglot-fsharp--sniff-method "fsharp/notifyWorkspace")))
+                       ;; (eglot-fsharp--sniff-method "fsharp/notifyWorkspace")
+                       )
+                     )
 
   (it "Can be invoked"
     ;; FIXME: Should use dotnet tool run
     (expect (process-file (eglot-fsharp--path-to-server) nil nil nil "--version")
-	    :to-equal 0))
+            :to-equal 0))
   (it "is enabled on F# Files"
     (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
       (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
-  (it "shows flymake errors"
-    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Error.fs")
-      (flymake-mode t)
-      (flymake-start)
-      (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
-      (goto-char (point-min))
-      (search-forward "nonexisting")
-      (insert "x")
-      (eglot--signal-textDocument/didChange)
-      (flymake-goto-next-error 1 '() t)
-      (expect (face-at-point) :to-be 'flymake-error )))
+  ;; (it "shows flymake errors"
+  ;;   (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Error.fs")
+  ;;     (flymake-mode t)
+  ;;     (flymake-start)
+  ;;     (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
+  ;;     (goto-char (point-min))
+  ;;     (search-forward "nonexisting")
+  ;;     (insert "x")
+  ;;     (eglot--signal-textDocument/didChange)
+  ;;     (flymake-goto-next-error 1 '() t)
+  ;;     (expect (face-at-point) :to-be 'flymake-error )))
   (it "provides completion"
     (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
       (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))

From 41f31e91e2632d1f51ce58a174531fdfc6098f13 Mon Sep 17 00:00:00 2001
From: 64J0 <vinigaio97@gmail.com>
Date: Fri, 7 Feb 2025 19:23:04 -0300
Subject: [PATCH 141/147] add pr template

---
 .github/pull_request_template.md | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 .github/pull_request_template.md

diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..e27a787
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,11 @@
+## Description
+
+<!-- Add a small description of the PR that you're submitting -->
+
+## How to test
+
+<!-- Please describe how one can test/verify that the PR is working (when applicable) -->
+
+## Related issues
+
+<!-- Point to the relevant issues addressed by this PR -->

From 08e6efa7c8d86f2684cbfba9afde9c2e86968414 Mon Sep 17 00:00:00 2001
From: 64J0 <vinigaio97@gmail.com>
Date: Tue, 25 Feb 2025 17:53:50 -0300
Subject: [PATCH 142/147] bump tests fsautocomplete version to 0.77.2

---
 test/integration-tests.el | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 65e7e07..6534f6c 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -34,9 +34,9 @@
 (unless (eq system-type 'windows-nt)
   (describe "F# LSP Installation"
             :before-all (setq latest-version (eglot-fsharp--latest-version))
-            (it "succeeds using version 0.52.0"
-                (eglot-fsharp--maybe-install "0.52.0")
-                (expect (eglot-fsharp--installed-version) :to-equal "0.52.0"))
+            (it "succeeds using version 0.77.2"
+                (eglot-fsharp--maybe-install "0.77.2")
+                (expect (eglot-fsharp--installed-version) :to-equal "0.77.2"))
             (it (format "succeeds using latest version: %s)" latest-version)
                 (eglot-fsharp--maybe-install)
                 (expect (eglot-fsharp--installed-version) :to-equal latest-version))))

From 466c04d800b46f3577744a166e696bfec998fe98 Mon Sep 17 00:00:00 2001
From: 64J0 <vinigaio97@gmail.com>
Date: Wed, 26 Feb 2025 19:08:17 -0300
Subject: [PATCH 143/147] uncomment broken tests

---
 test/integration-tests.el | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/test/integration-tests.el b/test/integration-tests.el
index 6534f6c..6fbe599 100644
--- a/test/integration-tests.el
+++ b/test/integration-tests.el
@@ -48,9 +48,7 @@
                      (eglot-fsharp--maybe-install)
                      (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
                        (eglot-fsharp--tests-connect 10)
-                       ;; (eglot-fsharp--sniff-method "fsharp/notifyWorkspace")
-                       )
-                     )
+                       (eglot-fsharp--sniff-method "fsharp/notifyWorkspace")))
 
   (it "Can be invoked"
     ;; FIXME: Should use dotnet tool run
@@ -59,17 +57,17 @@
   (it "is enabled on F# Files"
     (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
       (expect (type-of (eglot--current-server-or-lose)) :to-be 'eglot-fsautocomplete)))
-  ;; (it "shows flymake errors"
-  ;;   (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Error.fs")
-  ;;     (flymake-mode t)
-  ;;     (flymake-start)
-  ;;     (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
-  ;;     (goto-char (point-min))
-  ;;     (search-forward "nonexisting")
-  ;;     (insert "x")
-  ;;     (eglot--signal-textDocument/didChange)
-  ;;     (flymake-goto-next-error 1 '() t)
-  ;;     (expect (face-at-point) :to-be 'flymake-error )))
+  (it "shows flymake errors"
+    (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/Error.fs")
+      (flymake-mode t)
+      (flymake-start)
+      (eglot-fsharp--sniff-diagnostics "test/Test1/Error.fs")
+      (goto-char (point-min))
+      (search-forward "nonexisting")
+      (insert "x")
+      (eglot--signal-textDocument/didChange)
+      (flymake-goto-next-error 1 '() t)
+      (expect (face-at-point) :to-be 'flymake-error )))
   (it "provides completion"
     (with-current-buffer (eglot-fsharp--find-file-noselect "test/Test1/FileTwo.fs")
       (expect (plist-get (eglot--capabilities (eglot--current-server-or-lose)) :completionProvider) :not :to-be nil)))

From 4fe16b07518cad6caa5a2072a5b92309c0650885 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 21 Mar 2023 17:21:31 +0100
Subject: [PATCH 144/147] Add (failing) indentation test for first line after
 opening bracket

---
 test/fsharp-mode-structure-tests.el | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/test/fsharp-mode-structure-tests.el b/test/fsharp-mode-structure-tests.el
index dd6653b..7792b38 100644
--- a/test/fsharp-mode-structure-tests.el
+++ b/test/fsharp-mode-structure-tests.el
@@ -271,3 +271,11 @@
                 (should (eq (fsharp--compute-indentation-relative-to-previous t) 4))
                 (should (eq (fsharp--compute-indentation-relative-to-previous t)
 		            (fsharp-compute-indentation t))))))
+
+(describe "The `fsharp-compute-indentation'"
+          :var ((file (concat fsharp-struct-test-files-dir "BracketIndent.fs")))
+          (it "indents on the first line after opening bracket"
+              (with-current-buffer (find-file-noselect file)
+                (goto-char (point-min))
+                (search-forward-regexp "let formatTwo = \\[\n")
+                (should (eq (fsharp-compute-indentation t) fsharp-indent-offset)))))

From bb32718845beae427aba713203571daccdd5fea9 Mon Sep 17 00:00:00 2001
From: Juergen Hoetzel <juergen@hoetzel.info>
Date: Tue, 21 Mar 2023 17:22:26 +0100
Subject: [PATCH 145/147] Indentation: Handle first line after opening bracket

Fixes: "End position is smaller than start position" error.
---
 fsharp-mode-structure.el | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/fsharp-mode-structure.el b/fsharp-mode-structure.el
index b7664fb..30376a3 100644
--- a/fsharp-mode-structure.el
+++ b/fsharp-mode-structure.el
@@ -766,6 +766,10 @@ dedenting."
            (open-bracket-pos (fsharp-nesting-level)))
 
       (cond
+       ((and open-bracket-pos (eq (and (looking-back "[[:space:]\n\r]+" nil t)
+				       (match-beginning 0))
+				  (1+ open-bracket-pos)))
+	fsharp-indent-offset)
        ;; Continuation Lines
        ((fsharp-continuation-line-p)
         (if open-bracket-pos

From 135bc5996591966845549cd9d622f7aaf16385d8 Mon Sep 17 00:00:00 2001
From: dalu <mou.tong@outlook.com>
Date: Mon, 30 Jun 2025 14:53:29 +0800
Subject: [PATCH 146/147] Fix auto-mode-alist

---
 fsharp-mode.el | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fsharp-mode.el b/fsharp-mode.el
index 41199e6..82bd5d8 100644
--- a/fsharp-mode.el
+++ b/fsharp-mode.el
@@ -113,8 +113,9 @@
       (define-key map [eval-phrase] '("Eval phrase" . fsharp-eval-phrase)))))
 
 ;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.fs[iylx]?\\'" . fsharp-mode))
-(add-to-list 'auto-mode-alist '("\\.fsproj\\'" . nxml-mode))
+(progn
+  (add-to-list 'auto-mode-alist '("\\.fs[iylx]?\\'" . fsharp-mode))
+  (add-to-list 'auto-mode-alist '("\\.fsproj\\'" . nxml-mode)))
 
 (defvar fsharp-mode-syntax-table nil
   "Syntax table in use in fsharp mode buffers.")

From 015200493b93608dfd93a65a1301c0d289996e5c Mon Sep 17 00:00:00 2001
From: Jen-Chieh Shen <jcs090218@gmail.com>
Date: Mon, 28 Jul 2025 03:16:33 -0700
Subject: [PATCH 147/147] fix(README.org): Fix Eldev link

---
 README.org | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.org b/README.org
index 9d6c0bb..85839f1 100644
--- a/README.org
+++ b/README.org
@@ -183,7 +183,7 @@ This project is maintained by the
 [[http://fsharp.org/][F# Software Foundation]], with the repository hosted
 on [[https://github.com/fsharp/emacs-fsharp-mode][GitHub]].
 
-Pull requests are welcome. Please run the test-suite with [Eldev](https://doublep.github.io/eldev/) =eldev -dtT test=
+Pull requests are welcome. Please run the test-suite with [[https://doublep.github.io/eldev/][Eldev]] =eldev -dtT test=
 before submitting a pull request.
 
 *** Maintainers
