From e826b2fb8771f6ee475117405320f226cd31e194 Mon Sep 17 00:00:00 2001 From: cngimenez Date: Sat, 3 Jun 2023 16:43:24 -0300 Subject: [PATCH 01/25] Inferior-haskell: do not insert repeated prompts. --- inf-haskell.el | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/inf-haskell.el b/inf-haskell.el index 6462db99..e893badd 100644 --- a/inf-haskell.el +++ b/inf-haskell.el @@ -113,6 +113,25 @@ The format should be the same as for `compilation-error-regexp-alist'.") correctly interpret multi-line input even when modules are imported.") +(defconst inferior-haskell-cont-prompt-regexp + "^[[:alnum:].*_() |λ]*| " + "Continuation prompt rexep. +Used to remove them from the output by the comint preoutput filter. See +`inferior-haskell-remove-extra-prompts'. + +This should be a similar regexp as `haskell-prompt-regexp', but it usually +ends with \"| \" instead of \"> \".") + +(defconst inferior-haskell-maybe-cont-prompt-regexp + "^[[:alnum:].*_() |λ]*[>|] " + "A continuation or non-continuation prompt regexp. +This should match any prompt, a continuation or a common prompt. This regexp +should be similar to `haskell-prompt-regexp' and +`inferior-haskell-cont-prompt-regex' as it should match both. + +It is used to remove multiple prompts on the comint preoutput filter. See +`inferior-haskell-remove-extra-prompts'.") + ;;; TODO ;;; -> Make font lock work for strings, directories, hyperlinks ;;; -> Make font lock work for key words??? @@ -161,7 +180,40 @@ imported.") (define-key map keys (lookup-key compilation-minor-mode-map keys))) (add-to-list 'minor-mode-overriding-map-alist (cons 'compilation-minor-mode map)))) - (add-hook 'inferior-haskell-hook 'inferior-haskell-init)) + (add-hook 'inferior-haskell-hook 'inferior-haskell-init) + + ;; Avoid multiple prompts at the end of the output + (add-hook 'comint-preoutput-filter-functions + #'inferior-haskell-remove-extra-prompts nil t)) + +(defun inferior-haskell-remove-extra-prompts (str) + "Remove any extra Haskell-prompts from STR. +Remove multiple prompts from STR. All prompts indicating continuation are +completely removed. Only remain the last non-continuantion prompt. + +Examples: +The input \"Prelude> Prelude> \" will return \"Prelude> \". +The input \"Prelude| Prelude| \" will return \"\". + +These kind of output are usually produced by the multiple line input (i.e. when +using \":{ ... :}\" code in the GHCi interpreter). Sometimes, comint would note +filter the prompts out. For this reason, this function shoud be added to the +hook `comint-preoutput-filter-functions', to be executed before comint insert +STR to the buffer. + +Some libraries, such as ob-haskell.el, considers the multilple prompts as part +of the evaluation output. Moreover, it does not provide any information to the +user. Removing these prompts provides a better reading and less code for parsing +the output." + (let ((last-match nil)) + (while (string-match inferior-haskell-maybe-cont-prompt-regexp str) + (setq last-match (match-string 0 str)) + (setq str (substring str (match-end 0)))) + ;; Remove prompt-cont if it is the last one. + (if (or (null last-match) + (string-match inferior-haskell-cont-prompt-regexp last-match)) + str + (concat last-match str)))) (defvar inferior-haskell-buffer nil "The buffer in which the inferior process is running.") From 3392de68a1e9dd3c52a60ee8f90d8c1d63046462 Mon Sep 17 00:00:00 2001 From: Ken Takusagawa Date: Sun, 28 Apr 2024 04:28:19 -0400 Subject: [PATCH 02/25] Make dabbrev-expand detect underbar and prime as part of identifiers --- haskell-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell-mode.el b/haskell-mode.el index f8e7c3fb..bae5fb44 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -854,7 +854,7 @@ Minor modes that work well with `haskell-mode': (setq-local dabbrev-case-fold-search nil) (setq-local dabbrev-case-distinction nil) (setq-local dabbrev-case-replace nil) - (setq-local dabbrev-abbrev-char-regexp "\\sw\\|[.]") + (setq-local dabbrev-abbrev-char-regexp "\\sw\\|\\s_\\|[.]") (setq haskell-literate nil) (add-hook 'before-save-hook 'haskell-mode-before-save-handler nil t) (add-hook 'after-save-hook 'haskell-mode-after-save-handler nil t) From 5b1a6490646b48c9d84479f4fc31c7de2cec7122 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 04:29:25 +0000 Subject: [PATCH 03/25] chore(deps): bump cachix/install-nix-action from V27 to 28 Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from V27 to 28. This release includes the previously tagged commit. - [Release notes](https://github.com/cachix/install-nix-action/releases) - [Commits](https://github.com/cachix/install-nix-action/compare/V27...V28) --- updated-dependencies: - dependency-name: cachix/install-nix-action dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .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 1d2e0a43..28cb7e50 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: - emacs_version: 29.1 target: deploy-manual steps: - - uses: cachix/install-nix-action@V27 + - uses: cachix/install-nix-action@V28 with: nix_path: nixpkgs=channel:nixos-unstable - uses: purcell/setup-emacs@master From 126fcdafc8789f60a10329d11323f861e30229bb Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Sat, 14 Sep 2024 03:43:45 +1200 Subject: [PATCH 04/25] Include Emacs 29.4 in CI matrix See #1851 --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1d2e0a43..dc057643 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,9 +23,10 @@ jobs: - 28.1 - 28.2 - 29.1 + - 29.4 - snapshot include: - - emacs_version: 29.1 + - emacs_version: 29.4 target: deploy-manual steps: - uses: cachix/install-nix-action@V27 From 0a033f41c253a29a693bb8eaeb4e6037e46fc511 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 04:29:11 +0000 Subject: [PATCH 05/25] chore(deps): bump cachix/install-nix-action from V28 to 29 Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from V28 to 29. This release includes the previously tagged commit. - [Release notes](https://github.com/cachix/install-nix-action/releases) - [Commits](https://github.com/cachix/install-nix-action/compare/V28...v29) --- updated-dependencies: - dependency-name: cachix/install-nix-action dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .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 65eb96a1..40a84c1e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: - emacs_version: 29.4 target: deploy-manual steps: - - uses: cachix/install-nix-action@V28 + - uses: cachix/install-nix-action@v29 with: nix_path: nixpkgs=channel:nixos-unstable - uses: purcell/setup-emacs@master From cbb958ca4b8b2004f83820b8b0a49626046d3a5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 04:58:42 +0000 Subject: [PATCH 06/25] chore(deps): bump cachix/install-nix-action from 29 to 30 Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 29 to 30. - [Release notes](https://github.com/cachix/install-nix-action/releases) - [Commits](https://github.com/cachix/install-nix-action/compare/v29...v30) --- updated-dependencies: - dependency-name: cachix/install-nix-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .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 40a84c1e..6a76eec5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: - emacs_version: 29.4 target: deploy-manual steps: - - uses: cachix/install-nix-action@v29 + - uses: cachix/install-nix-action@v30 with: nix_path: nixpkgs=channel:nixos-unstable - uses: purcell/setup-emacs@master From a4e246e6f14616414541db8706615173e8a29cfa Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Fri, 8 Nov 2024 01:52:21 +0300 Subject: [PATCH 07/25] Optimize and simplify `haskell-ds-create-imenu-index` with hashtable The function has implemented a poor man's hash table by manually enlisting keys and then using `cl-case` on values. Just replace this with a hashtable and thus simplify the code considerably. This makes it faster as well because the `cl-case + setq` is O(n) whereas `puthash` is O(1). The output of the function was tested on Pandoc's `Writers/Powerpoint/Output.hs` file of 2841 lines and comparing the hashsum of the output before the changes and after. It didn't change. The commit is also basically a backport of a similar change on purescript-mode that has been forked form haskell-mode at some point: https://github.com/purescript-emacs/purescript-mode/pull/27 --- haskell-decl-scan.el | 55 +++++++++++--------------------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/haskell-decl-scan.el b/haskell-decl-scan.el index 2f4ddff2..f32515ac 100644 --- a/haskell-decl-scan.el +++ b/haskell-decl-scan.el @@ -106,6 +106,7 @@ (require 'haskell-mode) (require 'syntax) (require 'imenu) +(require 'subr-x) (defgroup haskell-decl-scan nil "Haskell declaration scanning (`imenu' support)." @@ -537,11 +538,7 @@ datatypes) in a Haskell file for the `imenu' package." ;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'. (let* ((bird-literate (haskell-ds-bird-p)) (index-alist '()) - (index-class-alist '()) ;; Classes - (index-var-alist '()) ;; Variables - (index-imp-alist '()) ;; Imports - (index-inst-alist '()) ;; Instances - (index-type-alist '()) ;; Datatypes + (imenu (make-hash-table :test 'equal)) ;; The result we wish to return. result) (goto-char (point-min)) @@ -557,47 +554,23 @@ datatypes) in a Haskell file for the `imenu' package." (posns (cdr name-posns)) (start-pos (car posns)) (type (cdr result))) - ;; Place `(name . start-pos)' in the correct alist. - (cl-case type - (variable - (setq index-var-alist - (cl-acons name start-pos index-var-alist))) - (datatype - (setq index-type-alist - (cl-acons name start-pos index-type-alist))) - (class - (setq index-class-alist - (cl-acons name start-pos index-class-alist))) - (import - (setq index-imp-alist - (cl-acons name start-pos index-imp-alist))) - (instance - (setq index-inst-alist - (cl-acons name start-pos index-inst-alist))))))) + (puthash type + (cons (cons name start-pos) (gethash type imenu '())) + imenu)))) ;; Now sort all the lists, label them, and place them in one list. - (when index-type-alist - (push (cons "Datatypes" - (sort index-type-alist 'haskell-ds-imenu-label-cmp)) - index-alist)) - (when index-inst-alist - (push (cons "Instances" - (sort index-inst-alist 'haskell-ds-imenu-label-cmp)) - index-alist)) - (when index-imp-alist - (push (cons "Imports" - (sort index-imp-alist 'haskell-ds-imenu-label-cmp)) - index-alist)) - (when index-class-alist - (push (cons "Classes" - (sort index-class-alist 'haskell-ds-imenu-label-cmp)) - index-alist)) - (when index-var-alist + (dolist (type '((datatype . "Datatypes") (instance . "Instances") + (import . "Imports") (class . "Classes"))) + (when-let ((curr-alist (gethash (car type) imenu))) + (push (cons (cdr type) + (sort curr-alist 'haskell-ds-imenu-label-cmp)) + index-alist))) + (when-let ((var-alist (gethash 'variable imenu))) (if haskell-decl-scan-bindings-as-variables (push (cons "Variables" - (sort index-var-alist 'haskell-ds-imenu-label-cmp)) + (sort var-alist 'haskell-ds-imenu-label-cmp)) index-alist) (setq index-alist (append index-alist - (sort index-var-alist 'haskell-ds-imenu-label-cmp))))) + (sort var-alist 'haskell-ds-imenu-label-cmp))))) ;; Return the alist. index-alist)) From 0c9c9cfc56bf9be658af4e84d1ee38d52671dad3 Mon Sep 17 00:00:00 2001 From: amesgen Date: Thu, 16 Jan 2025 14:39:10 +0100 Subject: [PATCH 08/25] Add GHC 9.12.1 extensions and options --- haskell-ghc-support.el | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/haskell-ghc-support.el b/haskell-ghc-support.el index 3a72fc82..3dabc5c5 100644 --- a/haskell-ghc-support.el +++ b/haskell-ghc-support.el @@ -103,7 +103,9 @@ "MonomorphismRestriction" "MultiParamTypeClasses" "MultiWayIf" + "MultilineStrings" "NPlusKPatterns" + "NamedDefaults" "NamedFieldPuns" "NamedWildCards" "NegativeLiterals" @@ -179,7 +181,9 @@ "NoMonomorphismRestriction" "NoMultiParamTypeClasses" "NoMultiWayIf" + "NoMultilineStrings" "NoNPlusKPatterns" + "NoNamedDefaults" "NoNamedFieldPuns" "NoNamedWildCards" "NoNegativeLiterals" @@ -187,6 +191,7 @@ "NoNullaryTypeClasses" "NoNumDecimals" "NoNumericUnderscores" + "NoOrPatterns" "NoOverlappingInstances" "NoOverloadedLabels" "NoOverloadedLists" @@ -249,6 +254,7 @@ "NullaryTypeClasses" "NumDecimals" "NumericUnderscores" + "OrPatterns" "OverlappingInstances" "OverloadedLabels" "OverloadedLists" @@ -524,6 +530,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-Werror=unused-record-wildcards" "-Werror=unused-top-binds" "-Werror=unused-type-patterns" + "-Werror=view-pattern-signatures" "-Werror=warnings-deprecations" "-Werror=wrong-do-bind" "-Weverything" @@ -720,6 +727,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-Wno-error=unused-record-wildcards" "-Wno-error=unused-top-binds" "-Wno-error=unused-type-patterns" + "-Wno-error=view-pattern-signatures" "-Wno-error=warnings-deprecations" "-Wno-error=wrong-do-bind" "-Wno-everything" @@ -815,6 +823,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-Wno-unused-record-wildcards" "-Wno-unused-top-binds" "-Wno-unused-type-patterns" + "-Wno-view-pattern-signatures" "-Wno-warnings-deprecations" "-Wno-wrong-do-bind" "-Wnoncanonical-monad-instances" @@ -864,6 +873,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-Wunused-record-wildcards" "-Wunused-top-binds" "-Wunused-type-patterns" + "-Wview-pattern-signatures" "-Wwarn" "-Wwarn=all" "-Wwarn=all-missed-specialisations" @@ -984,6 +994,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-Wwarn=unused-record-wildcards" "-Wwarn=unused-top-binds" "-Wwarn=unused-type-patterns" + "-Wwarn=view-pattern-signatures" "-Wwarn=warnings-deprecations" "-Wwarn=wrong-do-bind" "-Wwarnings-deprecations" @@ -1065,7 +1076,9 @@ This list should be updated by running `haskell-update-ghc-support'.") "-XMonomorphismRestriction" "-XMultiParamTypeClasses" "-XMultiWayIf" + "-XMultilineStrings" "-XNPlusKPatterns" + "-XNamedDefaults" "-XNamedFieldPuns" "-XNamedWildCards" "-XNegativeLiterals" @@ -1142,7 +1155,9 @@ This list should be updated by running `haskell-update-ghc-support'.") "-XNoMonomorphismRestriction" "-XNoMultiParamTypeClasses" "-XNoMultiWayIf" + "-XNoMultilineStrings" "-XNoNPlusKPatterns" + "-XNoNamedDefaults" "-XNoNamedFieldPuns" "-XNoNamedWildCards" "-XNoNegativeLiterals" @@ -1150,6 +1165,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-XNoNullaryTypeClasses" "-XNoNumDecimals" "-XNoNumericUnderscores" + "-XNoOrPatterns" "-XNoOverlappingInstances" "-XNoOverloadedLabels" "-XNoOverloadedLists" @@ -1212,6 +1228,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-XNullaryTypeClasses" "-XNumDecimals" "-XNumericUnderscores" + "-XOrPatterns" "-XOverlappingInstances" "-XOverloadedLabels" "-XOverloadedLists" @@ -1537,6 +1554,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-fexitification" "-fexpose-all-unfoldings" "-fexpose-internal-symbols" + "-fexpose-overloaded-unfoldings" "-fext-core" "-fextended-default-rules" "-fexternal-dynamic-refs" @@ -1592,6 +1610,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-flocal-float-out-top-level" "-floopification" "-fmax-errors" + "-fmax-forced-spec-args" "-fmax-inline-alloc-size" "-fmax-inline-memcpy-insns" "-fmax-inline-memset-insns" @@ -1662,6 +1681,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-fno-exitification" "-fno-expose-all-unfoldings" "-fno-expose-internal-symbols" + "-fno-expose-overloaded-unfoldings" "-fno-ext-core" "-fno-extended-default-rules" "-fno-external-dynamic-refs" @@ -1716,6 +1736,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-fno-mono-pat-binds" "-fno-monomorphism-restriction" "-fno-num-constant-folding" + "-fno-object-determinism" "-fno-omit-interface-pragmas" "-fno-omit-yields" "-fno-opt-coercion" @@ -1855,6 +1876,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-fno-write-interface" "-fnum-constant-folding" "-fobject-code" + "-fobject-determinism" "-fomit-interface-pragmas" "-fomit-yields" "-foptimal-applicative-do" @@ -2023,6 +2045,7 @@ This list should be updated by running `haskell-update-ghc-support'.") "-fworker-wrapper" "-fworker-wrapper-cbv" "-fwrite-ide-info" + "-fwrite-if-compression" "-fwrite-if-simplified-core" "-fwrite-interface" "-g" @@ -2100,7 +2123,9 @@ This list should be updated by running `haskell-update-ghc-support'.") "-o" "-odir" "-ohi" + "-optCmmP" "-optF" + "-optJSP" "-optL" "-optP" "-opta" @@ -2123,7 +2148,9 @@ This list should be updated by running `haskell-update-ghc-support'.") "-package-key" "-package-name" "-parallel" + "-pgmCmmP" "-pgmF" + "-pgmJSP" "-pgmL" "-pgmP" "-pgma" From a41e809986cb31422a4945e15c6683bb1b744c66 Mon Sep 17 00:00:00 2001 From: Zaz Brown Date: Sun, 2 Feb 2025 20:03:09 +0000 Subject: [PATCH 09/25] ensure run-expr uses *haskell* buffer Previously, it would run `(goto-char (point-max)) (insert "\n")` in whatever buffer you are currently in. --- haskell-repl.el | 57 +++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/haskell-repl.el b/haskell-repl.el index 58be6a23..8ce30dfe 100644 --- a/haskell-repl.el +++ b/haskell-repl.el @@ -70,34 +70,35 @@ "Run the given expression." (let ((session (haskell-interactive-session)) (process (haskell-interactive-process))) - (haskell-process-queue-command - process - (make-haskell-command - :state (list session process expr 0) - :go (lambda (state) - (goto-char (point-max)) - (insert "\n") - (setq haskell-interactive-mode-result-end - (point-max)) - (haskell-process-send-string (cadr state) - (haskell-interactive-mode-multi-line (cl-caddr state))) - (haskell-process-set-evaluating (cadr state) t)) - :live (lambda (state buffer) - (unless (and (string-prefix-p ":q" (cl-caddr state)) - (string-prefix-p (cl-caddr state) ":quit")) - (let* ((cursor (cl-cadddr state)) - (next (replace-regexp-in-string - haskell-process-prompt-regex - "" - (substring buffer cursor)))) - (haskell-interactive-mode-eval-result (car state) next) - (setf (cl-cdddr state) (list (length buffer))) - nil))) - :complete - (lambda (state response) - (haskell-process-set-evaluating (cadr state) nil) - (unless (haskell-interactive-mode-trigger-compile-error state response) - (haskell-interactive-mode-expr-result state response))))))) + (with-current-buffer (haskell-session-interactive-buffer session) + (haskell-process-queue-command + process + (make-haskell-command + :state (list session process expr 0) + :go (lambda (state) + (goto-char (point-max)) + (insert "\n") + (setq haskell-interactive-mode-result-end + (point-max)) + (haskell-process-send-string (cadr state) + (haskell-interactive-mode-multi-line (cl-caddr state))) + (haskell-process-set-evaluating (cadr state) t)) + :live (lambda (state buffer) + (unless (and (string-prefix-p ":q" (cl-caddr state)) + (string-prefix-p (cl-caddr state) ":quit")) + (let* ((cursor (cl-cadddr state)) + (next (replace-regexp-in-string + haskell-process-prompt-regex + "" + (substring buffer cursor)))) + (haskell-interactive-mode-eval-result (car state) next) + (setf (cl-cdddr state) (list (length buffer))) + nil))) + :complete + (lambda (state response) + (haskell-process-set-evaluating (cadr state) nil) + (unless (haskell-interactive-mode-trigger-compile-error state response) + (haskell-interactive-mode-expr-result state response)))))))) (defun haskell-interactive-mode-expr-result (state response) "Print the result of evaluating the expression." From 8ab625efe94aeffeb9e6427cb0af5329c52ab389 Mon Sep 17 00:00:00 2001 From: Zaz Brown Date: Mon, 3 Feb 2025 17:17:55 +0000 Subject: [PATCH 10/25] add function: C-c RET loads & runs current buffer Alternatively, C-c C-m can be used. --- haskell.el | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/haskell.el b/haskell.el index 1b358051..3bb546b8 100644 --- a/haskell.el +++ b/haskell.el @@ -38,6 +38,7 @@ (defvar interactive-haskell-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-l") 'haskell-process-load-file) + (define-key map (kbd "C-c RET") 'haskell-load-and-run) ;; == C-c C-m (define-key map (kbd "C-c C-r") 'haskell-process-reload) (define-key map (kbd "C-c C-t") 'haskell-process-do-type) (define-key map (kbd "C-c C-i") 'haskell-process-do-info) @@ -397,6 +398,12 @@ Give optional NEXT-P parameter to override value of nil (current-buffer))) +(defun haskell-load-and-run () + "Loads the current buffer and runs the main function." + (interactive) + (haskell-process-load-file) + (haskell-interactive-mode-run-expr "main")) + ;;;###autoload (defun haskell-process-reload () "Re-load the current buffer file." From 238bb6262218d5eed02ce7a9cec54c07f9c8cad4 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Thu, 6 Feb 2025 11:32:01 +0000 Subject: [PATCH 11/25] add haskell-load-and-run-expr-history --- haskell.el | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/haskell.el b/haskell.el index 3bb546b8..eae8d2b9 100644 --- a/haskell.el +++ b/haskell.el @@ -398,11 +398,16 @@ Give optional NEXT-P parameter to override value of nil (current-buffer))) -(defun haskell-load-and-run () - "Loads the current buffer and runs the main function." - (interactive) +(defvar haskell-load-and-run-expr-history nil + "History of expressions used in `haskell-load-and-run'.") + +(defun haskell-load-and-run (expr) + "Load the current buffer and run EXPR, e.g. \"main\"." + (interactive (list (read-string "Run expression: " + (car haskell-load-and-run-expr-history) + 'haskell-load-and-run-expr-history))) (haskell-process-load-file) - (haskell-interactive-mode-run-expr "main")) + (haskell-interactive-mode-run-expr expr)) ;;;###autoload (defun haskell-process-reload () From d7b05e4b047d34d73278ce81ec2d355d1a5d1c83 Mon Sep 17 00:00:00 2001 From: Pablo Castellanos Date: Sun, 9 Feb 2025 19:18:06 +0100 Subject: [PATCH 12/25] Add user option to preserve the order of imenu candidates --- haskell-decl-scan.el | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/haskell-decl-scan.el b/haskell-decl-scan.el index f32515ac..8299f34e 100644 --- a/haskell-decl-scan.el +++ b/haskell-decl-scan.el @@ -124,6 +124,11 @@ :group 'haskell-decl-scan :type 'boolean) +(defcustom haskell-decl-scan-sort-imenu t + "Whether to sort the candidates in imenu." + :group 'haskell-decl-scan + :type 'boolean) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; General declaration scanning functions. @@ -562,15 +567,21 @@ datatypes) in a Haskell file for the `imenu' package." (import . "Imports") (class . "Classes"))) (when-let ((curr-alist (gethash (car type) imenu))) (push (cons (cdr type) - (sort curr-alist 'haskell-ds-imenu-label-cmp)) + (if haskell-decl-scan-sort-imenu + (sort curr-alist 'haskell-ds-imenu-label-cmp) + (reverse curr-alist))) index-alist))) (when-let ((var-alist (gethash 'variable imenu))) (if haskell-decl-scan-bindings-as-variables (push (cons "Variables" - (sort var-alist 'haskell-ds-imenu-label-cmp)) + (if haskell-decl-scan-sort-imenu + (sort var-alist 'haskell-ds-imenu-label-cmp) + (reverse var-alist))) index-alist) (setq index-alist (append index-alist - (sort var-alist 'haskell-ds-imenu-label-cmp))))) + (if haskell-decl-scan-sort-imenu + (sort var-alist 'haskell-ds-imenu-label-cmp) + (reverse var-alist)))))) ;; Return the alist. index-alist)) From 2163e0d8373885789f74c39c214c33a7ea7a59b5 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Mon, 24 Feb 2025 15:48:00 +0000 Subject: [PATCH 13/25] Revert "Inferior-haskell: do not insert repeated prompts." This reverts commit e826b2fb8771f6ee475117405320f226cd31e194. See #1806 and #1867 --- inf-haskell.el | 54 +------------------------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/inf-haskell.el b/inf-haskell.el index e893badd..6462db99 100644 --- a/inf-haskell.el +++ b/inf-haskell.el @@ -113,25 +113,6 @@ The format should be the same as for `compilation-error-regexp-alist'.") correctly interpret multi-line input even when modules are imported.") -(defconst inferior-haskell-cont-prompt-regexp - "^[[:alnum:].*_() |λ]*| " - "Continuation prompt rexep. -Used to remove them from the output by the comint preoutput filter. See -`inferior-haskell-remove-extra-prompts'. - -This should be a similar regexp as `haskell-prompt-regexp', but it usually -ends with \"| \" instead of \"> \".") - -(defconst inferior-haskell-maybe-cont-prompt-regexp - "^[[:alnum:].*_() |λ]*[>|] " - "A continuation or non-continuation prompt regexp. -This should match any prompt, a continuation or a common prompt. This regexp -should be similar to `haskell-prompt-regexp' and -`inferior-haskell-cont-prompt-regex' as it should match both. - -It is used to remove multiple prompts on the comint preoutput filter. See -`inferior-haskell-remove-extra-prompts'.") - ;;; TODO ;;; -> Make font lock work for strings, directories, hyperlinks ;;; -> Make font lock work for key words??? @@ -180,40 +161,7 @@ It is used to remove multiple prompts on the comint preoutput filter. See (define-key map keys (lookup-key compilation-minor-mode-map keys))) (add-to-list 'minor-mode-overriding-map-alist (cons 'compilation-minor-mode map)))) - (add-hook 'inferior-haskell-hook 'inferior-haskell-init) - - ;; Avoid multiple prompts at the end of the output - (add-hook 'comint-preoutput-filter-functions - #'inferior-haskell-remove-extra-prompts nil t)) - -(defun inferior-haskell-remove-extra-prompts (str) - "Remove any extra Haskell-prompts from STR. -Remove multiple prompts from STR. All prompts indicating continuation are -completely removed. Only remain the last non-continuantion prompt. - -Examples: -The input \"Prelude> Prelude> \" will return \"Prelude> \". -The input \"Prelude| Prelude| \" will return \"\". - -These kind of output are usually produced by the multiple line input (i.e. when -using \":{ ... :}\" code in the GHCi interpreter). Sometimes, comint would note -filter the prompts out. For this reason, this function shoud be added to the -hook `comint-preoutput-filter-functions', to be executed before comint insert -STR to the buffer. - -Some libraries, such as ob-haskell.el, considers the multilple prompts as part -of the evaluation output. Moreover, it does not provide any information to the -user. Removing these prompts provides a better reading and less code for parsing -the output." - (let ((last-match nil)) - (while (string-match inferior-haskell-maybe-cont-prompt-regexp str) - (setq last-match (match-string 0 str)) - (setq str (substring str (match-end 0)))) - ;; Remove prompt-cont if it is the last one. - (if (or (null last-match) - (string-match inferior-haskell-cont-prompt-regexp last-match)) - str - (concat last-match str)))) + (add-hook 'inferior-haskell-hook 'inferior-haskell-init)) (defvar inferior-haskell-buffer nil "The buffer in which the inferior process is running.") From 648d7c2e753d0cd9e978ba2f9bef3b3dc53e315d Mon Sep 17 00:00:00 2001 From: Commelina Date: Wed, 26 Feb 2025 12:34:38 +0200 Subject: [PATCH 14/25] haskell-cabal: fix indentation with leading commas and newlines --- haskell-cabal.el | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/haskell-cabal.el b/haskell-cabal.el index c0707009..244df1b8 100644 --- a/haskell-cabal.el +++ b/haskell-cabal.el @@ -474,8 +474,20 @@ Possible results are \\='section-header \\='subsection-header \\='section-data :end (save-match-data (haskell-cabal-subsection-end)) :data-start-column (save-excursion (goto-char (match-end 0)) (current-column)) + ;; Note: Redundant leading commas are allowed since Cabal 2.2. + ;; Example: + ;; build-depends: + ;; , base + ;; , text + ;; + ;; Note: More than one newlines are allowed after the subsection name. + ;; Example: + ;; build-depends: + ;; + ;; + ;; base :data-indent-column (save-excursion (goto-char (match-end 0)) - (when (looking-at "\n +\\(\\w*\\)") (goto-char (match-beginning 1))) + (when (looking-at "\n[\n\t ]* +\\([\\w,]*\\)") (goto-char (match-beginning 1))) (current-column) ))))) @@ -1058,11 +1070,24 @@ Source names from main-is and c-sources sections are left untouched (cl-case (haskell-cabal-classify-line) (section-data (save-excursion - (let ((indent (haskell-cabal-section-data-indent-column - (haskell-cabal-subsection)))) - (indent-line-to indent) + (let* ((subsection (haskell-cabal-subsection)) + (beginning (haskell-cabal-section-start subsection)) + (indent-column (haskell-cabal-section-data-indent-column subsection)) + (subsection-leading-comma-p (save-excursion + (goto-char beginning) + (looking-at ",\\|\n[ \t\n]*,")))) + (indent-line-to indent-column) (beginning-of-line) - (when (looking-at "[ ]*\\([ ]\\{2\\},[ ]*\\)") + ;; Only do extra adjustment if the first item is not comma leading. + ;; Example of the two cases: + ;; + ;; | aaa | aaa + ;; | , bbb | , bbb + ;; + ;; | , aaa | , aaa + ;; | , bbb | , bbb + (when (and (not subsection-leading-comma-p) + (looking-at "[ ]*\\([ ]\\{2\\},[ ]*\\)")) (replace-match ", " t t nil 1))))) (empty (indent-relative))) From 497811f322459b88c999535c34b861536e45727d Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 4 Mar 2025 18:39:59 +0300 Subject: [PATCH 15/25] haskell-cabal: fix (comment-dwim) by correcting comment-start-skip Prior to this commit using (comment-dwim) over a comment in .cabal file that doesn't start at the beginning of a line resulted in it adding even more comments. E.g. this: -- comment not at the beginning of a line resulted in: -- -- comment not at the beginning of a line This is because `comment-start-skip` was including whitespace that isn't part of the comment syntax. Fix this by only limiting the regexp to the comment part. The resulting regexp is basically same as the one in haskell-mode, barring that that one also takes into account `{-` comment starter, which isn't a thing in .cabal files. Fixes: https://github.com/haskell/haskell-mode/issues/1743 --- haskell-cabal.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell-cabal.el b/haskell-cabal.el index c0707009..4f2ab579 100644 --- a/haskell-cabal.el +++ b/haskell-cabal.el @@ -175,7 +175,7 @@ it from list if one of the following conditions are hold: (add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local) (add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local) (setq-local comment-start "-- ") - (setq-local comment-start-skip "\\(^[ \t]*\\)--[ \t]*") + (setq-local comment-start-skip "--[ \t]*") (setq-local comment-end "") (setq-local comment-end-skip "[ \t]*\\(\\s>\\|\n\\)") (setq-local indent-line-function 'haskell-cabal-indent-line) From 5604aabfb82de59c5e4b0459b01a1db4bb63a4cb Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 4 Mar 2025 18:47:29 +0300 Subject: [PATCH 16/25] haskell-cabal: don't include space in `comment-start` The point of this space is to add padding, however in Emacs comment padding is controlled by `comment-padding` which defaults to one space exactly. --- haskell-cabal.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell-cabal.el b/haskell-cabal.el index c0707009..4db3eb5b 100644 --- a/haskell-cabal.el +++ b/haskell-cabal.el @@ -174,7 +174,7 @@ it from list if one of the following conditions are hold: (add-to-list 'haskell-cabal-buffers (current-buffer)) (add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local) (add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local) - (setq-local comment-start "-- ") + (setq-local comment-start "--") (setq-local comment-start-skip "\\(^[ \t]*\\)--[ \t]*") (setq-local comment-end "") (setq-local comment-end-skip "[ \t]*\\(\\s>\\|\n\\)") From 511aa3568c0f2c39919753036067eb5e4efb0f30 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 5 Mar 2025 01:45:48 +0300 Subject: [PATCH 17/25] haskell-c2hs.el: don't quote face inside a list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A face is represented by a symbol, however representing a symbol inside lists requires no quoting. So remove the quote. Fixes warning: haskell-c2hs.el:37:19: Error: in defface for ‘haskell-c2hs-hook-pair-face’: Value for face attribute ‘:inherit’ should not be quoted --- haskell-c2hs.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haskell-c2hs.el b/haskell-c2hs.el index 8eb31ff8..092f4753 100644 --- a/haskell-c2hs.el +++ b/haskell-c2hs.el @@ -34,12 +34,12 @@ (add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) (defface haskell-c2hs-hook-pair-face - '((t (:inherit 'font-lock-preprocessor-face))) + '((t (:inherit font-lock-preprocessor-face))) "Face for highlighting {#...#} pairs." :group 'haskell) (defface haskell-c2hs-hook-name-face - '((t (:inherit 'font-lock-keyword-face))) + '((t (:inherit font-lock-keyword-face))) "Face for highlighting c2hs hook names." :group 'haskell) From 48dfdfa52d137b9d7148d5a196e567c624e6fa53 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 5 Mar 2025 01:50:06 +0300 Subject: [PATCH 18/25] haskell-commands.el: clarify list type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: haskell-commands.el:49:10: Error: in defcustom for ‘haskell-mode-stylish-haskell-args’: ‘list’ without arguments --- haskell-commands.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell-commands.el b/haskell-commands.el index f9ed3da4..c9ae488b 100644 --- a/haskell-commands.el +++ b/haskell-commands.el @@ -46,7 +46,7 @@ (defcustom haskell-mode-stylish-haskell-args nil "Arguments to pass to program specified by haskell-mode-stylish-haskell-path." :group 'haskell - :type 'list) + :type '(list string)) (defcustom haskell-interactive-set-+c t From 0c9454a59aa80ba11d842760404eefbf55a7cc2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 04:13:07 +0000 Subject: [PATCH 19/25] chore(deps): bump cachix/install-nix-action from 30 to 31 Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 30 to 31. - [Release notes](https://github.com/cachix/install-nix-action/releases) - [Commits](https://github.com/cachix/install-nix-action/compare/v30...v31) --- updated-dependencies: - dependency-name: cachix/install-nix-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .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 6a76eec5..7517b4ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: - emacs_version: 29.4 target: deploy-manual steps: - - uses: cachix/install-nix-action@v30 + - uses: cachix/install-nix-action@v31 with: nix_path: nixpkgs=channel:nixos-unstable - uses: purcell/setup-emacs@master From c9e76ddd22496009505b9b4190d01d67b16ccf72 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Tue, 1 Apr 2025 18:18:36 +0100 Subject: [PATCH 20/25] Remove no-op unwind-protect forms (bytecomp warning) --- haskell-commands.el | 5 ++--- haskell.el | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/haskell-commands.el b/haskell-commands.el index c9ae488b..992bb9c9 100644 --- a/haskell-commands.el +++ b/haskell-commands.el @@ -769,9 +769,8 @@ inferior GHCi process." (haskell-session-set-target session target) (when (not (string= old-target target)) (haskell-mode-toggle-interactive-prompt-state) - (unwind-protect - (when (y-or-n-p "Target changed, restart haskell process? ") - (haskell-process-start session))) + (when (y-or-n-p "Target changed, restart haskell process? ") + (haskell-process-start session)) (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload diff --git a/haskell.el b/haskell.el index eae8d2b9..33e7ac7b 100644 --- a/haskell.el +++ b/haskell.el @@ -167,11 +167,10 @@ (interactive) (when (eq major-mode 'haskell-interactive-mode) (haskell-mode-toggle-interactive-prompt-state) - (unwind-protect - (when (and (boundp 'haskell-session) - haskell-session - (y-or-n-p "Kill the whole session? ")) - (haskell-session-kill t))) + (when (and (boundp 'haskell-session) + haskell-session + (y-or-n-p "Kill the whole session? ")) + (haskell-session-kill t)) (haskell-mode-toggle-interactive-prompt-state t))) (defun haskell-session-make (name) @@ -223,13 +222,12 @@ If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (when (not (string= name "")) (let ((session (haskell-session-lookup name))) (haskell-mode-toggle-interactive-prompt-state) - (unwind-protect - (if session - (when - (y-or-n-p - (format "Session %s already exists. Use it?" name)) - session) - (haskell-session-make name))) + (if session + (when + (y-or-n-p + (format "Session %s already exists. Use it?" name)) + session) + (haskell-session-make name)) (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload From 26b134a0303b4ac4cf08f81c7c004a0f747e77a1 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Tue, 1 Apr 2025 18:18:54 +0100 Subject: [PATCH 21/25] Fix quoting in docstring (bytecode warning) See #1875 --- haskell-commands.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haskell-commands.el b/haskell-commands.el index 992bb9c9..dd6fb99c 100644 --- a/haskell-commands.el +++ b/haskell-commands.el @@ -710,9 +710,9 @@ function `xref-find-definitions' after new table was generated." (haskell-mode-message-line "Tags generated.")))))) (defun haskell-process-add-cabal-autogen () - "Add cabal's autogen dir to the GHCi search path. + "Add the cabal autogen dir to the GHCi search path. Add /dist/build/autogen/ to GHCi seatch path. -This allows modules such as 'Path_...', generated by cabal, to be +This allows modules such as \"Path_...\", generated by cabal, to be loaded by GHCi." (unless (eq 'cabal-repl (haskell-process-type)) (let* From e85acb09d29fece3ec335cc6d94bd50b8577dac6 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Tue, 1 Apr 2025 18:19:11 +0100 Subject: [PATCH 22/25] Fix defcustom types (bytecomp warning) --- haskell-customize.el | 2 +- w3m-haddock.el | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/haskell-customize.el b/haskell-customize.el index dccddc7a..3ed41aff 100644 --- a/haskell-customize.el +++ b/haskell-customize.el @@ -394,7 +394,7 @@ hindent, structured-haskell-mode, tool-de-jour, etc. You can set this per-project with a .dir-locals.el file" :group 'haskell - :type '(repeat 'string)) + :type '(repeat string)) (defcustom haskell-stylish-on-save nil "Whether to run stylish-haskell on the buffer before saving. diff --git a/w3m-haddock.el b/w3m-haddock.el index 0f6a9e11..59b118bf 100644 --- a/w3m-haddock.el +++ b/w3m-haddock.el @@ -54,7 +54,7 @@ You can rebind this if you're using hsenv by adding it to your " :group 'haskell - :type 'list) + :type '(list string)) (defvar w3m-haddock-entry-regex "^\\(\\(data\\|type\\) \\|[a-z].* :: \\)" "Regex to match entry headings.") From 3112f5f4a5de9658b409e9994d0038962b01cb2b Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Tue, 1 Apr 2025 18:19:34 +0100 Subject: [PATCH 23/25] Remove no-op cond clause (bytecomp warning) --- haskell-indentation.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/haskell-indentation.el b/haskell-indentation.el index 4c252512..1576741b 100644 --- a/haskell-indentation.el +++ b/haskell-indentation.el @@ -1135,8 +1135,7 @@ layout starts." (haskell-indentation-add-indentation (+ left-indent haskell-indentation-starter-offset)) (throw 'parse-end nil)) - (setq phrase1 (cddr phrase))) - ((string= (cadr phrase) "in")))))) + (setq phrase1 (cddr phrase))))))) (defun haskell-indentation-add-indentation (indent) "" ; FIXME From 2e08ba771ffdc46d082b2285c534afdb12efb941 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Mon, 19 May 2025 12:54:54 +0100 Subject: [PATCH 24/25] Shell-quote directory name when building cabal command Fixes #1798 --- haskell-load.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell-load.el b/haskell-load.el index 48e75e2e..29804a56 100644 --- a/haskell-load.el +++ b/haskell-load.el @@ -252,7 +252,7 @@ list of modules where missed IDENT was found." (haskell-process-send-string (cadr state) (format haskell-process-do-cabal-format-string - (haskell-session-cabal-dir (car state)) + (shell-quote-argument (haskell-session-cabal-dir (car state))) (format "%s %s" app-name (cl-caddr state))))) :live (lambda (state buffer) From 4ce37fcc5f43acfb3966687475dbfb0fb3f97e7e Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Tue, 1 Jul 2025 07:31:17 +1200 Subject: [PATCH 25/25] Add Emacs 30.1 to CI matrix --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7517b4ad..4b92963e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,6 +24,7 @@ jobs: - 28.2 - 29.1 - 29.4 + - 30.1 - snapshot include: - emacs_version: 29.4