From 3dc7298e659c14ddaff74a99ea0317a3d67521ae Mon Sep 17 00:00:00 2001 From: Axel Forsman Date: Mon, 22 Feb 2021 14:54:19 +0100 Subject: [PATCH 01/99] Fix indent of case expr matching multiple values Makes parsing not fail for case expressions that match multiple expressions at once, such as case a, b of Just 1, Just 1 -> 1 _, _ -> 0 This syntax was added in PureScript v0.8.0. See: https://github.com/purescript/documentation/blob/master/language/Syntax.md#case-expressions --- purescript-indentation.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 4a66a0c..781ae94 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -529,7 +529,7 @@ autofill-mode." ("rec" . (lambda () (purescript-indentation-with-starter #'purescript-indentation-expression-layout nil))) ("case" . (lambda () (purescript-indentation-phrase - '(purescript-indentation-expression + `(,(lambda () (purescript-indentation-separated #'purescript-indentation-expression "," nil)) "of" purescript-indentation-case-layout)))) ("\\" . (lambda () (purescript-indentation-with-starter #'purescript-indentation-lambda-maybe-lambdacase nil))) @@ -713,7 +713,7 @@ autofill-mode." (end (parse-error "Illegal token: %s" current-token)))))) (defun purescript-indentation-case () - (purescript-indentation-expression) + (purescript-indentation-separated #'purescript-indentation-expression "," nil) (cond ((eq current-token 'end-tokens) (purescript-indentation-add-indentation current-indent)) ((string= current-token "|") From 0acd1af446424ba855153161fe07a20f67dc0a89 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Fri, 26 Mar 2021 15:30:06 +1300 Subject: [PATCH 02/99] Add Emacs 27.2 to CI matrix --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b828bd5..10f7f15 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,7 @@ jobs: - 26.2 - 26.3 - 27.1 + - 27.2 - snapshot steps: - uses: purcell/setup-emacs@master From 9c37067e611b5253a095f03245c247aa97bd7614 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Mon, 4 Apr 2022 14:52:40 +0200 Subject: [PATCH 03/99] Add Emacs 28.1 to CI matrix --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10f7f15..57381f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,7 @@ jobs: - 26.3 - 27.1 - 27.2 + - 28.1 - snapshot steps: - uses: purcell/setup-emacs@master From 41799aa3679a9f6d86b218c7aea53fef06d86fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Ho=C5=82ubowicz?= Date: Thu, 1 Sep 2022 11:32:31 +0200 Subject: [PATCH 04/99] Add syntax highlighting for `ado` --- purescript-font-lock.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 7a579b1..e0e3556 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -178,8 +178,8 @@ Returns keywords suitable for `font-lock-keywords'." ;; spec syntax, but they are not reserved. ;; `_' can go in here since it has temporary word syntax. (regexp-opt - '("case" "class" "data" "default" "deriving" "do" - "else" "if" "import" "in" "infix" "infixl" + '("ado" "case" "class" "data" "default" "deriving" + "do" "else" "if" "import" "in" "infix" "infixl" "infixr" "instance" "let" "module" "newtype" "of" "then" "type" "where" "_") 'words)) From 53c4675d555787e5386176861ff38987065a1d39 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 12 Sep 2024 18:05:00 +0300 Subject: [PATCH 05/99] purescript-indentation.el: don't modify buffer if indentation unchanged Currently calling indentation on a line that is already indented as expected results in buffer being modified despite no changes being actually done. Avoid this by checking if current indentation already matches the one we just calculated and only reindenting on mismatch. --- purescript-indentation.el | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 781ae94..0adec57 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -196,17 +196,18 @@ autofill-mode." (end-of-line)))) (defun purescript-indentation-reindent (col) - (beginning-of-line) - (delete-region (point) - (progn - (when (and (eq purescript-literate 'bird) - (eq (char-after) ?>)) - (forward-char)) - (skip-syntax-forward "-") - (point))) - (when (eq purescript-literate 'bird) - (insert ">")) - (indent-to col)) + (unless (= col (purescript-indentation-current-indentation)) + (beginning-of-line) + (delete-region (point) + (progn + (when (and (eq purescript-literate 'bird) + (eq (char-after) ?>)) + (forward-char)) + (skip-syntax-forward "-") + (point))) + (when (eq purescript-literate 'bird) + (insert ">")) + (indent-to col))) (defun purescript-indentation-current-indentation () (if (eq purescript-literate 'bird) From c3d297cf66ff9c6f91df84297794ea8dbd1e8e96 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 12 Sep 2024 18:22:35 +0300 Subject: [PATCH 06/99] purescript-indentation.el: improve visibility into local variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turning on lexical-binding fixes a bunch of warnings like: purescript-indentation.el:399:47: Warning: ‘pi’ is an obsolete variable (as of 23.3); use ‘float-pi’ instead. these warnings are caused by Emacs not being able to determine that `pi` is actually a local variable. By making use of lexical binding we make Emacs to be able to see through that. --- purescript-indentation.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 781ae94..1312553 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -1,4 +1,4 @@ -;;; purescript-indentation.el -- indentation module for PureScript Mode +;;; purescript-indentation.el -- indentation module for PureScript Mode -*- lexical-binding: t -*- ;; Copyright (C) 2009 Kristof Bastiaensen From c95d9e7288722932b5002c5acc17a3a5a530fbf0 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 30 Sep 2024 09:31:45 +0300 Subject: [PATCH 07/99] Fix "docstring wider than 80 characters" errors --- purescript-indent.el | 3 ++- purescript-mode.el | 4 +++- purescript-move-nested.el | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/purescript-indent.el b/purescript-indent.el index eec177f..700940b 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -432,7 +432,8 @@ Returns the location of the start of the comment, nil otherwise." (purescript-indent-skip-blanks-and-newlines-forward end)))) (defun purescript-indent-next-symbol-safe (end) - "Puts point to the next following symbol, or to end if there are no more symbols in the sexp." + "Puts point to the next following symbol, or to end if there are no more +symbols in the sexp." (condition-case errlist (purescript-indent-next-symbol end) (error (goto-char end)))) diff --git a/purescript-mode.el b/purescript-mode.el index dc20508..78d1c15 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -445,7 +445,9 @@ is asked to show extra info for the items matching QUERY.." :safe 'integerp) (defun purescript-mode-suggest-indent-choice () - "Ran when the user tries to indent in the buffer but no indentation mode has been selected. + "Ran when the user tries to indent in the buffer but no indentation mode +has been selected. + Brings up the documentation for purescript-mode-hook." (describe-variable 'purescript-mode-hook)) diff --git a/purescript-move-nested.el b/purescript-move-nested.el index 43b948e..dc5e26a 100644 --- a/purescript-move-nested.el +++ b/purescript-move-nested.el @@ -34,7 +34,8 @@ ;;;###autoload (defun purescript-move-nested (cols) - "Shift the nested off-side-rule block adjacent to point by COLS columns to the right. + "Shift the nested off-side-rule block adjacent to point by COLS columns +to the right. In Transient Mark mode, if the mark is active, operate on the contents of the region instead. From aa052e3f4d46669c535ff702676c122c25c6b419 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 30 Sep 2024 09:50:26 +0300 Subject: [PATCH 08/99] Escape single quotes in docstrings Fixes warnings: purescript-font-lock.el:448:2: Error: docstring has wrong usage of unescaped single quotes (use \=' or different quoting such as `...') purescript-indent.el:1321:2: Error: docstring has wrong usage of unescaped single quotes (use \=' or different quoting such as `...') purescript-mode.el:88:2: Error: docstring has wrong usage of unescaped single quotes (use \=' or different quoting such as `...') --- purescript-font-lock.el | 10 +++++----- purescript-indent.el | 2 +- purescript-mode.el | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index e0e3556..812f9b1 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -448,7 +448,7 @@ that should be commented under LaTeX-style literate scripts." (defun turn-on-purescript-font-lock () "Turns on font locking in current buffer for PureScript 1.4 scripts. -Changes the current buffer's `font-lock-defaults', and adds the +Changes the current buffer\\='s `font-lock-defaults', and adds the following variables: `purescript-keyword-face' for reserved keywords and syntax, @@ -470,7 +470,7 @@ Use the variable `font-lock-maximum-decoration' to choose non-default levels of fontification. For example, adding this to .emacs: - (setq font-lock-maximum-decoration '((purescript-mode . 2) (t . 0))) + (setq font-lock-maximum-decoration \\='((purescript-mode . 2) (t . 0))) uses level two fontification for `purescript-mode' and default level for all other modes. See documentation on this variable for further @@ -480,9 +480,9 @@ To alter an attribute of a face, add a hook. For example, to change the foreground colour of comments to brown, add the following line to .emacs: - (add-hook 'purescript-font-lock-hook + (add-hook \\='purescript-font-lock-hook (lambda () - (set-face-foreground 'purescript-comment-face \"brown\"))) + (set-face-foreground \\='purescript-comment-face \"brown\"))) Note that the colours available vary from system to system. To see what colours are available on your system, call @@ -490,7 +490,7 @@ what colours are available on your system, call To turn font locking on for all PureScript buffers, add this to .emacs: - (add-hook 'purescript-mode-hook 'turn-on-purescript-font-lock) + (add-hook \\='purescript-mode-hook \\='turn-on-purescript-font-lock) To turn font locking on for the current buffer, call `turn-on-purescript-font-lock'. To turn font locking off in the current diff --git a/purescript-indent.el b/purescript-indent.el index 700940b..95c169e 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -1321,7 +1321,7 @@ of the regions to move." (defun purescript-indent-align-def (p-arg type) "Align guards or rpurs within the current definition before point. If P-ARG is t align all defs up to the mark. -TYPE is either 'guard or 'rpurs." +TYPE is either \\='guard or \\='rpurs." (save-excursion (let (start-block end-block (maxcol (if (eq type 'rpurs) purescript-indent-rpurs-align-column 0)) diff --git a/purescript-mode.el b/purescript-mode.el index 78d1c15..068e494 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -87,7 +87,7 @@ When MESSAGE is non-nil, display a message with the version." ;;;###autoload (defun purescript-customize () "Browse the purescript customize sub-tree. -This calls 'customize-browse' with purescript as argument and makes +This calls `customize-browse' with purescript as argument and makes sure all purescript customize definitions have been loaded." (interactive) ;; make sure all modules with (defcustom ...)s are loaded From a01fc3c2a550873b4e2d4ff13e6922ddb2af9f4f Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 30 Sep 2024 10:05:27 +0300 Subject: [PATCH 09/99] purescript-mode.el: don't start variable used with an underscore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's reserved for unused variables. Fixes a warning: purescript-mode.el:63:11: Error: variable ‘_version’ not left unused --- purescript-mode.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index 068e494..c2be498 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -60,13 +60,13 @@ When MESSAGE is non-nil, display a message with the version." (interactive "P") (let* ((purescript-mode-dir (ignore-errors (file-name-directory (or (locate-library "purescript-mode") "")))) - (_version (format "purescript-mode version %s (%s @ %s)" + (version (format "purescript-mode version %s (%s @ %s)" purescript-version purescript-git-version purescript-mode-dir))) (if here - (insert _version) - (message "%s" _version)))) + (insert version) + (message "%s" version)))) ;;;###autoload (defun purescript-mode-view-news () From d98ad00c38b8843578ccd28e65ce57383a0fdd90 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 30 Sep 2024 09:52:32 +0300 Subject: [PATCH 10/99] Remove/rename unused lexical arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: purescript-indent.el:437:19: Error: Unused lexical variable ‘errlist’ purescript-indent.el:1295:34: Error: Unused lexical argument ‘start’ purescript-mode.el:416:44: Error: Unused lexical argument ‘info’ --- purescript-indent.el | 8 ++++---- purescript-mode.el | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/purescript-indent.el b/purescript-indent.el index 95c169e..5404fb6 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -434,7 +434,7 @@ Returns the location of the start of the comment, nil otherwise." (defun purescript-indent-next-symbol-safe (end) "Puts point to the next following symbol, or to end if there are no more symbols in the sexp." - (condition-case errlist (purescript-indent-next-symbol end) + (condition-case nil (purescript-indent-next-symbol end) (error (goto-char end)))) (defun purescript-indent-separate-valdef (start end) @@ -1292,7 +1292,7 @@ We stay in the cycle as long as the TAB key is pressed." (if marker (goto-char (marker-position marker))))))) -(defun purescript-indent-region (start end) +(defun purescript-indent-region (_start _end) (error "Auto-reindentation of a region is not supported")) ;;; alignment functions @@ -1430,9 +1430,9 @@ TYPE is either \\='guard or \\='rpurs." (if regstack (purescript-indent-shift-columns maxcol regstack))))))) -(defun purescript-indent-align-guards-and-rpurs (start end) +(defun purescript-indent-align-guards-and-rpurs (_start _end) "Align the guards and rpurs of functions in the region, which must be active." - ;; The `start' and `end' args are dummys right now: they're just there so + ;; The `_start' and `_end' args are dummys right now: they're just there so ;; we can use the "r" interactive spec which properly signals an error. (interactive "*r") (purescript-indent-align-def t 'guard) diff --git a/purescript-mode.el b/purescript-mode.el index c2be498..5609810 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -413,7 +413,7 @@ see documentation for that variable for more details." ;;;###autoload(add-to-list 'auto-mode-alist '("\\.purs\\'" . purescript-mode)) -(defun purescript-pursuit (query &optional info) +(defun purescript-pursuit (query &optional _info) "Do a Pursuit search for QUERY. When `purescript-pursuit-command' is non-nil, this command runs that. Otherwise, it opens a Pursuit search result in the browser. From c8dad403038ee7b819c0aec6d8b65835d92cbfa8 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 30 Sep 2024 10:13:20 +0300 Subject: [PATCH 11/99] Remove unused let-binding for `point` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: purescript-navigate-imports.el:101:12: Error: Unused lexical variable ‘point’ purescript-simple-indent.el:146:10: Error: Unused lexical variable ‘point’ --- purescript-navigate-imports.el | 7 +++---- purescript-simple-indent.el | 25 ++++++++++++------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/purescript-navigate-imports.el b/purescript-navigate-imports.el index 037f597..0c4c806 100644 --- a/purescript-navigate-imports.el +++ b/purescript-navigate-imports.el @@ -98,10 +98,9 @@ (purescript-navigate-imports-after-imports-p) ;; This one just speeds it up. (purescript-navigate-imports-line))) (forward-line)) - (let ((point (point))) - (if (purescript-navigate-imports-line) - (point) - nil)))) + (if (purescript-navigate-imports-line) + (point) + nil))) (defun purescript-navigate-imports-line () "Try to match the current line as a regexp." diff --git a/purescript-simple-indent.el b/purescript-simple-indent.el index 1b5d36c..2690f0c 100644 --- a/purescript-simple-indent.el +++ b/purescript-simple-indent.el @@ -143,19 +143,18 @@ column, `tab-to-tab-stop' is done instead." (defun purescript-simple-indent-newline-same-col () "Make a newline and go to the same column as the current line." (interactive) - (let ((point (point))) - (let ((start-end - (save-excursion - (let* ((start (line-beginning-position)) - (end (progn (goto-char start) - (search-forward-regexp - "[^ ]" (line-end-position) t 1)))) - (when end (cons start (1- end))))))) - (if start-end - (progn (newline) - (insert (buffer-substring-no-properties - (car start-end) (cdr start-end)))) - (newline))))) + (let ((start-end + (save-excursion + (let* ((start (line-beginning-position)) + (end (progn (goto-char start) + (search-forward-regexp + "[^ ]" (line-end-position) t 1)))) + (when end (cons start (1- end))))))) + (if start-end + (progn (newline) + (insert (buffer-substring-no-properties + (car start-end) (cdr start-end)))) + (newline)))) (defun purescript-simple-indent-newline-indent () "Make a newline on the current column and indent on step." From 7eacda36f9ee310e2115a7753cbca5e0e7726698 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 30 Sep 2024 10:14:49 +0300 Subject: [PATCH 12/99] purescript-sort-imports.el: make sure (interactive) is after docstring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: purescript-sort-imports.el:41:4: Error: Doc string after ‘interactive’ --- purescript-sort-imports.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purescript-sort-imports.el b/purescript-sort-imports.el index d46cecb..a1374ca 100644 --- a/purescript-sort-imports.el +++ b/purescript-sort-imports.el @@ -38,12 +38,12 @@ ;;;###autoload (defun purescript-sort-imports () - (interactive) "Sort the import list at point. It sorts the current group i.e. an import list separated by blank lines on either side. If the region is active, it will restrict the imports to sort within that region." + (interactive) (when (purescript-sort-imports-at-import) (let* ((points (purescript-sort-imports-decl-points)) (current-string (buffer-substring-no-properties (car points) From 9a9f55043872b9621286c5e2752f7f09fb07450e Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 30 Sep 2024 09:39:30 +0300 Subject: [PATCH 13/99] Enable lexical binding in all .el files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream Emacs has made lack of the directive a warning. So enable it explicitly everywhere. It provides various benefits such as better introspection by the compiler into the code and optimizations. Fixes a bunch of warnings: Error: file has no ‘lexical-binding’ directive on its first line --- purescript-align-imports.el | 2 +- purescript-collapse.el | 2 +- purescript-decl-scan.el | 2 +- purescript-font-lock.el | 2 +- purescript-indent.el | 2 +- purescript-indentation.el | 2 +- purescript-mode.el | 2 +- purescript-move-nested.el | 2 +- purescript-navigate-imports.el | 2 +- purescript-presentation-mode.el | 2 +- purescript-show.el | 2 +- purescript-simple-indent.el | 2 +- purescript-sort-imports.el | 2 +- purescript-str.el | 2 +- purescript-string.el | 1 + purescript-unicode-input-method.el | 2 +- purescript-utils.el | 2 +- purescript-yas.el | 2 +- tests/haskell-sort-imports-tests.el | 2 +- 19 files changed, 19 insertions(+), 18 deletions(-) diff --git a/purescript-align-imports.el b/purescript-align-imports.el index 56eabe2..5c36611 100644 --- a/purescript-align-imports.el +++ b/purescript-align-imports.el @@ -1,4 +1,4 @@ -;;; purescript-align-imports.el --- Align the import lines in a PureScript file +;;; purescript-align-imports.el --- Align the import lines in a PureScript file -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done diff --git a/purescript-collapse.el b/purescript-collapse.el index d6ddb92..e090644 100644 --- a/purescript-collapse.el +++ b/purescript-collapse.el @@ -1,4 +1,4 @@ -;;; purescript-collapse.el --- Collapse expressions +;;; purescript-collapse.el --- Collapse expressions -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. diff --git a/purescript-decl-scan.el b/purescript-decl-scan.el index f588cba..b3b61ed 100644 --- a/purescript-decl-scan.el +++ b/purescript-decl-scan.el @@ -1,4 +1,4 @@ -;;; purescript-decl-scan.el --- Declaration scanning module for PureScript Mode +;;; purescript-decl-scan.el --- Declaration scanning module for PureScript Mode -*- lexical-binding: t -*- ;; Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. ;; Copyright (C) 1997-1998 Graeme E Moss diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 812f9b1..85d4b7d 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -1,4 +1,4 @@ -;;; purescript-font-lock.el --- Font locking module for PureScript Mode +;;; purescript-font-lock.el --- Font locking module for PureScript Mode -*- lexical-binding: t -*- ;; Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ;; Copyright 1997-1998 Graeme E Moss, and Tommy Thorn diff --git a/purescript-indent.el b/purescript-indent.el index 5404fb6..05a1c34 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -1,4 +1,4 @@ -;;; purescript-indent.el --- "semi-intelligent" indentation module for PureScript Mode +;;; purescript-indent.el --- "semi-intelligent" indentation module for PureScript Mode -*- lexical-binding: t -*- ;; Copyright 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. ;; Copyright 1997-1998 Guy Lapalme diff --git a/purescript-indentation.el b/purescript-indentation.el index 5f8cea3..52c849b 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -1,4 +1,4 @@ -;;; purescript-indentation.el -- indentation module for PureScript Mode -*- lexical-binding: t -*- +;;; purescript-indentation.el -- indentation module for PureScript Mode -*- lexical-binding: t -*- -*- lexical-binding: t -*- ;; Copyright (C) 2009 Kristof Bastiaensen diff --git a/purescript-mode.el b/purescript-mode.el index 5609810..205c67e 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -1,4 +1,4 @@ -;;; purescript-mode.el --- A PureScript editing mode -*- coding: utf-8 -*- +;;; purescript-mode.el --- A PureScript editing mode -*- coding: utf-8 lexical-binding: t -*- ;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc ;; Copyright (C) 1992, 1997-1998 Simon Marlow, Graeme E Moss, and Tommy Thorn diff --git a/purescript-move-nested.el b/purescript-move-nested.el index dc5e26a..98a2f6d 100644 --- a/purescript-move-nested.el +++ b/purescript-move-nested.el @@ -1,4 +1,4 @@ -;;; purescript-move-nested.el --- Change the column of text nested below a line +;;; purescript-move-nested.el --- Change the column of text nested below a line -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done diff --git a/purescript-navigate-imports.el b/purescript-navigate-imports.el index 0c4c806..749f8ad 100644 --- a/purescript-navigate-imports.el +++ b/purescript-navigate-imports.el @@ -1,4 +1,4 @@ -;;; purescript-navigate-imports.el --- A function for cycling through PureScript import lists +;;; purescript-navigate-imports.el --- A function for cycling through PureScript import lists -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done diff --git a/purescript-presentation-mode.el b/purescript-presentation-mode.el index 54c3c33..1a8fa9b 100644 --- a/purescript-presentation-mode.el +++ b/purescript-presentation-mode.el @@ -1,4 +1,4 @@ -;;; purescript-presentation-mode.el --- Presenting PureScript things +;;; purescript-presentation-mode.el --- Presenting PureScript things -*- lexical-binding: t -*- ;; Copyright (C) 2013 Chris Done diff --git a/purescript-show.el b/purescript-show.el index 63a6d97..f380329 100644 --- a/purescript-show.el +++ b/purescript-show.el @@ -1,4 +1,4 @@ -;;; purescript-show.el --- A pretty printer for PureScript Show values +;;; purescript-show.el --- A pretty printer for PureScript Show values -*- lexical-binding: t -*- ;; Copyright (C) 2011 Chris Done diff --git a/purescript-simple-indent.el b/purescript-simple-indent.el index 2690f0c..5c0cf5e 100644 --- a/purescript-simple-indent.el +++ b/purescript-simple-indent.el @@ -1,4 +1,4 @@ -;;; purescript-simple-indent.el --- Simple indentation module for PureScript Mode +;;; purescript-simple-indent.el --- Simple indentation module for PureScript Mode -*- lexical-binding: t -*- ;; Copyright (C) 1998 Heribert Schuetz, Graeme E Moss diff --git a/purescript-sort-imports.el b/purescript-sort-imports.el index a1374ca..c635ada 100644 --- a/purescript-sort-imports.el +++ b/purescript-sort-imports.el @@ -1,4 +1,4 @@ -;;; purescript-sort-imports.el --- Sort the list of PureScript imports at the point alphabetically +;;; purescript-sort-imports.el --- Sort the list of PureScript imports at the point alphabetically -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done diff --git a/purescript-str.el b/purescript-str.el index 6e960d0..8f6c3a3 100644 --- a/purescript-str.el +++ b/purescript-str.el @@ -1,4 +1,4 @@ -;;; purescript-str.el --- PureScript related string utilities +;;; purescript-str.el --- PureScript related string utilities -*- lexical-binding: t -*- ;; Copyright (C) 2013 Herbert Valerio Riedel diff --git a/purescript-string.el b/purescript-string.el index b8a74af..23af498 100644 --- a/purescript-string.el +++ b/purescript-string.el @@ -1,3 +1,4 @@ +;;; purescript-string.el --- string manipulation utilties -*- lexical-binding: t -*- ;;;###autoload (defun purescript-trim (string) (replace-regexp-in-string diff --git a/purescript-unicode-input-method.el b/purescript-unicode-input-method.el index 15cc7a0..da5f521 100644 --- a/purescript-unicode-input-method.el +++ b/purescript-unicode-input-method.el @@ -1,4 +1,4 @@ -;;; purescript-unicode-input-method.el --- PureScript Unicode helper functions -*- coding: utf-8 -*- +;;; purescript-unicode-input-method.el --- PureScript Unicode helper functions -*- coding: utf-8 lexical-binding: t -*- ;; Copyright (C) 2010-2011 Roel van Dijk diff --git a/purescript-utils.el b/purescript-utils.el index 294dcfb..5651e87 100644 --- a/purescript-utils.el +++ b/purescript-utils.el @@ -1,4 +1,4 @@ -;;; purescript-utils.el --- General utility functions used by purescript-mode modules +;;; purescript-utils.el --- General utility functions used by purescript-mode modules -*- lexical-binding: t -*- ;; Copyright (C) 2013 Herbert Valerio Riedel diff --git a/purescript-yas.el b/purescript-yas.el index 08339ef..a531e73 100644 --- a/purescript-yas.el +++ b/purescript-yas.el @@ -1,4 +1,4 @@ -;;; purescript-yas.el --- Customization support for Luke Hoersten's yasnippets +;;; purescript-yas.el --- Customization support for Luke Hoersten's yasnippets -*- lexical-binding: t -*- ;; Copyright (C) 2013 John Wiegley, Luke Hoersten diff --git a/tests/haskell-sort-imports-tests.el b/tests/haskell-sort-imports-tests.el index 656bdd0..7670fb2 100644 --- a/tests/haskell-sort-imports-tests.el +++ b/tests/haskell-sort-imports-tests.el @@ -1,4 +1,4 @@ -;;; purescript-sort-imports-tests.el --- Unit tests for purescript-sort-imports +;;; purescript-sort-imports-tests.el --- Unit tests for purescript-sort-imports -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. From cc34919659bdba7269f5628266c7bc6e6a74fe2b Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 2 Oct 2024 18:24:38 +0300 Subject: [PATCH 14/99] Never fail to indent A proper indentation engine should never look past the previous line. This is because a user frequently wants custom indentation, in all programming languages. A PureScript example: ```haskell f1 x = case x of true -> true _ -> false f2 x = case x of true -> true _ -> false ``` So the proper behavior is: "take previous-line indentation, then if previous line has a modifier increase/decrease it". This is both simple, robust, typically meets the user expectations, and is AFAIK what all built-in major modes do. Unfortunately we're long past that point, the purescript-mode indentation engine parses a lot of stuff it shouldn't. And frequently it gives a "parsing error". In my experience all those "errors" are bugs because the PS code is perfectly valid, but disregarding if it's a bug or an actual unfinished code in the buffer, engine should never leave a user with no indentation whatsoever. So what this commit does is it detects such "errors", and takes previous indentation level. Even if it's not the correct indentation, in practice it's only off by `purescript-indentation-left-offset`, so a user often has much less to type compared to "no indentation" at all. ------- Now, it turns out the mode has another bug. As explained in the function being added, `purescript-newline-and-indent` calls indentation calculations on the wrong line. This isn't some special code that only `purescript-newline-and-indent` uses, it is a code that's being called by the TAB indentation as well. As there are huge amounts of poorly documented code that shouldn't even be there in the first place, and are sometimes using local variables from other functions, I decided instead of trying to fix the code it would be more productive to just detect whether we're being called from `purescript-newline-and-indent` or not. --- purescript-indentation.el | 46 +++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 52c849b..41d0bc1 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -463,21 +463,39 @@ autofill-mode." (defun purescript-indentation-first-indentation () (if (eq purescript-literate 'bird) '(2) '(0))) +(defun purescript-get-previous-indentation-hack () + "Return previous indentation level as a list element. + +This function is a temporary workaround for +`purescript-newline-and-indent' asking for indent before going to the +new line, which makes it indistinguishable from just attempting to +indent the current line. This has to be fixed elsewhere." + (list + (if (string= this-command "purescript-newline-and-indent") + (current-indentation) ;; current line is actually previous one + (save-excursion + (forward-line -1) + (current-indentation))))) + (defun purescript-indentation-find-indentations () - (let ((ppss (syntax-ppss))) - (cond - ((nth 3 ppss) - (purescript-indentation-first-indentation)) - ((nth 4 ppss) - (if (save-excursion - (and (skip-syntax-forward "-") - (eolp) - (not (> (forward-line 1) 0)) - (not (nth 4 (syntax-ppss))))) - (purescript-indentation-parse-to-indentations) - (purescript-indentation-first-indentation))) - (t - (purescript-indentation-parse-to-indentations))))) + (condition-case nil + (let ((ppss (syntax-ppss))) + (cond + ((nth 3 ppss) + (purescript-indentation-first-indentation)) + ((nth 4 ppss) + (if (save-excursion + (and (skip-syntax-forward "-") + (eolp) + (not (> (forward-line 1) 0)) + (not (nth 4 (syntax-ppss))))) + (purescript-indentation-parse-to-indentations) + (purescript-indentation-first-indentation))) + (t + (purescript-indentation-parse-to-indentations)))) + ;; Ideally it should not return parse error but if it does just use the previous + ;; indentation. + (parse-error (purescript-get-previous-indentation-hack)))) (defconst purescript-indentation-unicode-tokens '(("→" . "->") ;; #x2192 RIGHTWARDS ARROW From 5bb1da1291e340e3c3dc51fc6a856635a2025568 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 8 Oct 2024 12:46:19 +0300 Subject: [PATCH 15/99] Avoid redefining conflict marker faces from smerge-mode Whenever conflicts appear in Emacs buffer, they get handled by smerge-mode. The mode isn't enabled by default, but it gets turned on upon conflict markers entering the buffer. There's no point in redefining what's already handled by Emacs. --- purescript-font-lock.el | 3 --- 1 file changed, 3 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 85d4b7d..9d6b65a 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -205,9 +205,6 @@ Returns keywords suitable for `font-lock-keywords'." (setq keywords `(;; NOTICE the ordering below is significant ;; - ("^<<<<<<< .*$" 0 'font-lock-warning-face t) - ("^=======" 0 'font-lock-warning-face t) - ("^>>>>>>> .*$" 0 'font-lock-warning-face t) ("^#.*$" 0 'font-lock-preprocessor-face t) (,reservedid 1 (symbol-value 'purescript-keyword-face)) From ba3e997b1b6e57b9f19aeea783ae8b2fc499c4dd Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 8 Oct 2024 13:16:51 +0300 Subject: [PATCH 16/99] Don't highlight top-level-only keywords at different levels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The keywords being modified here only represented keywords when they are at the beginning of a line with optional indentation. At different levels these would represent valid record fields or other identifiers. This was tested by adding the following code to a PureScript file: type Foo = { type :: Int , module :: Int , import :: Int , data :: Int , class :: Int , newtype :: Int } …and checking that compilation succeeds. --- purescript-font-lock.el | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 85d4b7d..f13840b 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -172,16 +172,22 @@ Returns keywords suitable for `font-lock-keywords'." ;; "@" "~" "=>") t) "\\(->\\|\\.\\.\\|::\\|∷\\|<-\\|=>\\|[=@\\|~]\\)" "\\S_")) + ;; These are only keywords when appear at top-level, optionally with + ;; indentation. They are not reserved and in other levels would represent + ;; record fields or other identifiers. + (toplevel-keywords + (rx line-start (zero-or-more whitespace) + (group (or "type" "module" "import" "data" "class" "newtype" + "instance") + word-end))) ;; Reserved identifiers (reservedid ;; `as', `hiding', and `qualified' are part of the import ;; spec syntax, but they are not reserved. ;; `_' can go in here since it has temporary word syntax. (regexp-opt - '("ado" "case" "class" "data" "default" "deriving" - "do" "else" "if" "import" "in" "infix" "infixl" - "infixr" "instance" "let" "module" "newtype" "of" - "then" "type" "where" "_") 'words)) + '("ado" "case" "default" "deriving" "do" "else" "if" "in" "infix" + "infixl" "infixr" "let" "of" "then" "where" "_") 'words)) ;; Top-level declarations (topdecl-var @@ -210,6 +216,7 @@ Returns keywords suitable for `font-lock-keywords'." ("^>>>>>>> .*$" 0 'font-lock-warning-face t) ("^#.*$" 0 'font-lock-preprocessor-face t) + (,toplevel-keywords 1 (symbol-value 'purescript-keyword-face)) (,reservedid 1 (symbol-value 'purescript-keyword-face)) (,reservedsym 1 (symbol-value 'purescript-operator-face)) ;; Special case for `as', `hiding', `safe' and `qualified', which are From b6d68e3276c8e4417d4635d6df64727dab1a4805 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 6 Nov 2024 00:22:54 +0300 Subject: [PATCH 17/99] Implement going to the beginning of a defun MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements support for `(beginning-of-defun)`. As a side note, the match is done inside a single line string because I tried implementing a regexp to make Emacs to restrain to a single line, and it turned out to be very hard. I didn't succeed at that for like ½-hour I spent, and constraining the search artifically turned out not just much easier, but also significantly simplified the regexp. --- purescript-mode.el | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/purescript-mode.el b/purescript-mode.el index 205c67e..56a7255 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -340,6 +340,7 @@ see documentation for that variable for more details." (set (make-local-variable 'dabbrev-case-distinction) nil) (set (make-local-variable 'dabbrev-case-replace) nil) (set (make-local-variable 'dabbrev-abbrev-char-regexp) "\\sw\\|[.]") + (setq-local beginning-of-defun-function 'purescript-beginning-of-defun) (setq prettify-symbols-alist purescript-font-lock-prettify-symbols-alist) (when (bound-and-true-p purescript-font-lock-symbols) (warn "`purescript-font-lock-symbols' is obsolete: please enable `prettify-symbols-mode' locally or globally instead.")) @@ -470,6 +471,35 @@ Brings up the documentation for purescript-mode-hook." (format " [ %s .. ]" (purescript-string-take (purescript-trim (cadr lines)) 10)) "")))))) +(defun purescript-current-line-string () + "Returns current line as a string." + (buffer-substring-no-properties (line-beginning-position) (line-end-position))) + +(defun purescript-beginning-of-defun-single () + (while (and (looking-at-p (rx (* space) eol)) + (not (bobp))) + (forward-line -1)) ; can't get indentation on an empty line + (let ((indent-level (current-indentation))) + (while + (not + (or (ignore (forward-line -1)) ; do-while implementation + (bobp) + (and (< (current-indentation) indent-level) + (string-match-p + (rx (*? anything) + (or bol space word-boundary) "=" + (or eol space word-boundary)) + ;; Emacs doesn't allow to limit search just to the curent line + ;; barring the regex eol, but eol overly complicates matching. + (purescript-current-line-string)))))))) + +(defun purescript-beginning-of-defun (&optional repeat) + "Move point to the beginning of the current PureScript function." + (purescript-beginning-of-defun-single) + (dotimes (_ (if repeat + (- repeat 1) ; the function was already called once + 0)) + (purescript-beginning-of-defun-single))) (provide 'purescript-mode) From bc7d7e949d42e0795b96cd41ed741a587a4f3258 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 11 Nov 2024 18:17:52 +0300 Subject: [PATCH 18/99] Compile purescript-decl-scsan.el file as well --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index ad2d8c7..91a391c 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ ELFILES = \ purescript-string.el \ purescript-unicode-input-method.el \ purescript-utils.el \ + purescript-decl-scan.el \ purescript-yas.el ELCFILES = $(ELFILES:.el=.elc) From e42b14785f852409dfbadb95c8750b9128331b54 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 6 Nov 2024 02:45:51 +0300 Subject: [PATCH 19/99] Migrate `purescript-ds-create-imenu-index` to hashtables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function has implemented a poor man's hash table by manually enlisting keys and then jumping through the hoops by fetching them from one place, converting values to symbols to values… In particular, it was using `symbol-value` to map a symbol to its value, however the symbol was a local variable, and `symbol-value` doesn't work with them under lexical-binding, which the file was converted to since commit 9a9f550. So fix the regression and simplify the code at the same time. Fixes: https://github.com/purescript-emacs/purescript-mode/issues/25 --- purescript-decl-scan.el | 54 ++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/purescript-decl-scan.el b/purescript-decl-scan.el index b3b61ed..7af65b7 100644 --- a/purescript-decl-scan.el +++ b/purescript-decl-scan.el @@ -104,6 +104,7 @@ (require 'syntax) (require 'cl-lib) (require 'imenu) +(require 'subr-x) (defgroup purescript-decl-scan nil "PureScript declaration scanning (`imenu' support)." @@ -453,6 +454,12 @@ positions and the type is one of the symbols \"variable\", \"datatype\", ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Declaration scanning via `imenu'. +(defmacro purescript-when-let (spec &rest body) + "A wrapper to silence `when-let' deprecation warning" + (if (fboundp 'when-let*) + (list 'when-let* spec (macroexp-progn body)) + (with-no-warnings (list 'when-let spec (macroexp-progn body))))) + ;;;###autoload (defun purescript-ds-create-imenu-index () "Function for finding `imenu' declarations in PureScript mode. @@ -462,11 +469,7 @@ datatypes) in a PureScript file for the `imenu' package." ;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'. (let* ((bird-literate (purescript-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)) ;; Variables for showing progress. (bufname (buffer-name)) (divisor-of-progress (max 1 (/ (buffer-size) 100))) @@ -486,40 +489,25 @@ datatypes) in a PureScript file for the `imenu' package." (name (car name-posns)) (posns (cdr name-posns)) (start-pos (car posns)) - (type (cdr result)) - ;; Place `(name . start-pos)' in the correct alist. - (sym (cdr (assq type - '((variable . index-var-alist) - (datatype . index-type-alist) - (class . index-class-alist) - (import . index-imp-alist) - (instance . index-inst-alist)))))) - (set sym (cons (cons name start-pos) (symbol-value sym)))))) + (type (cdr result))) + (puthash type + (cons (cons name start-pos) (gethash type imenu '())) + imenu)))) ;; Now sort all the lists, label them, and place them in one list. (message "Sorting declarations in %s..." bufname) - (when index-type-alist - (push (cons "Datatypes" - (sort index-type-alist 'purescript-ds-imenu-label-cmp)) - index-alist)) - (when index-inst-alist - (push (cons "Instances" - (sort index-inst-alist 'purescript-ds-imenu-label-cmp)) - index-alist)) - (when index-imp-alist - (push (cons "Imports" - (sort index-imp-alist 'purescript-ds-imenu-label-cmp)) - index-alist)) - (when index-class-alist - (push (cons "Classes" - (sort index-class-alist 'purescript-ds-imenu-label-cmp)) - index-alist)) - (when index-var-alist + (dolist (type '((datatype . "Datatypes") (instance . "Instances") + (import . "Imports") (class . "Classes"))) + (purescript-when-let ((curr-alist (gethash (car type) imenu))) + (push (cons (cdr type) + (sort curr-alist 'purescript-ds-imenu-label-cmp)) + index-alist))) + (purescript-when-let ((var-alist (gethash 'variable imenu))) (if purescript-decl-scan-bindings-as-variables (push (cons "Variables" - (sort index-var-alist 'purescript-ds-imenu-label-cmp)) + (sort var-alist 'purescript-ds-imenu-label-cmp)) index-alist) (setq index-alist (append index-alist - (sort index-var-alist 'purescript-ds-imenu-label-cmp))))) + (sort var-alist 'purescript-ds-imenu-label-cmp))))) (message "Sorting declarations in %s...done" bufname) ;; Return the alist. index-alist)) From 0a8aebba3b5aa3ae991991ce5392e481d0056efc Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 9 Dec 2024 21:20:14 +0300 Subject: [PATCH 20/99] Rename keyword "deriving" to "derive" PureScript, as opposed to Haskell, doesn't seem to have `deriving` as a keyword. I grepped over `purescript` compiler `tests/` directory to be sure. Instead it has `derive` keyword, which is a top level one that serves similar purpose to "deriving". So rename `deriving` to `derive`. --- purescript-font-lock.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index f13840b..25ebc9a 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -178,7 +178,7 @@ Returns keywords suitable for `font-lock-keywords'." (toplevel-keywords (rx line-start (zero-or-more whitespace) (group (or "type" "module" "import" "data" "class" "newtype" - "instance") + "instance" "derive") word-end))) ;; Reserved identifiers (reservedid @@ -186,7 +186,7 @@ Returns keywords suitable for `font-lock-keywords'." ;; spec syntax, but they are not reserved. ;; `_' can go in here since it has temporary word syntax. (regexp-opt - '("ado" "case" "default" "deriving" "do" "else" "if" "in" "infix" + '("ado" "case" "default" "do" "else" "if" "in" "infix" "infixl" "infixr" "let" "of" "then" "where" "_") 'words)) ;; Top-level declarations From 32938fcd74d025479d9c8972411aa003d473e6de Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 7 Oct 2024 22:23:37 +0300 Subject: [PATCH 21/99] Implement ability to switch from .purs to .js FFI file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emacs provides a `(ff-find-other-file nil t)` function to switch between header and implementations. The closest PureScript has to such idea is the FFI, where given `Foo.purs` there has to be similarly named `Foo.js`, and unsurprisingly I keep pressing a keybind trying to switch between them. So add the mapping from `.purs` to `.js`. Worth noting that this doesn't provide the reverse mapping `.js → .purs` because js is a different major mode and we can't be making assumptions on whether it's related to PureScript… Usually. We probably could reassign in case the js file was open by the `ff-find-other-file`, but let's keep it simple for now. --- purescript-mode.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/purescript-mode.el b/purescript-mode.el index 56a7255..f7f9d38 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -37,6 +37,7 @@ (require 'purescript-string) (require 'purescript-font-lock) (require 'cl-lib) +(cl-eval-when 'compile (require 'find-file)) ;; All functions/variables start with `(literate-)purescript-'. @@ -341,7 +342,9 @@ see documentation for that variable for more details." (set (make-local-variable 'dabbrev-case-replace) nil) (set (make-local-variable 'dabbrev-abbrev-char-regexp) "\\sw\\|[.]") (setq-local beginning-of-defun-function 'purescript-beginning-of-defun) - (setq prettify-symbols-alist purescript-font-lock-prettify-symbols-alist) + (setq prettify-symbols-alist purescript-font-lock-prettify-symbols-alist + ;; make (ff-find-other-file) find .js FFI file, given .purs + ff-other-file-alist '((".purs\\'" (".js")))) (when (bound-and-true-p purescript-font-lock-symbols) (warn "`purescript-font-lock-symbols' is obsolete: please enable `prettify-symbols-mode' locally or globally instead.")) ) From e36b995d207f034a89beab8fab3752c7e6d21ae7 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 7 Nov 2024 20:19:39 +0300 Subject: [PATCH 22/99] Remove `default` keyword I just stumbled upon a code in PS `routing-duplex`, where `default` is a function name and it's getting highlighted. That made me dig to see where such keyword could be used to reduce the possibility of such false-positives. Now, I personally don't remember `default` being ever used as a keyword in PS. So I asked an AI but it doesn't know either. Then as a last measure I looked at syntax highlight in VS Code editor, and they don't highlight `default` either. So remove `default` from the list of keywords. --- purescript-font-lock.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index e1a0610..f642ac6 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -186,7 +186,7 @@ Returns keywords suitable for `font-lock-keywords'." ;; spec syntax, but they are not reserved. ;; `_' can go in here since it has temporary word syntax. (regexp-opt - '("ado" "case" "default" "do" "else" "if" "in" "infix" + '("ado" "case" "do" "else" "if" "in" "infix" "infixl" "infixr" "let" "of" "then" "where" "_") 'words)) ;; Top-level declarations From 09327cb992ef8b0a7f4666c44353f6b069d38d68 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 9 Dec 2024 23:12:43 +0300 Subject: [PATCH 23/99] Remove "deriving" Haskell artifact from indentation `deriving` isn't a thing in PureScript. There's `derive` keyword, but it has a bit different structure (specifically, it is a top-level keyword). Related discussion: https://discourse.purescript.org/t/solved-is-deriving-keyword-a-thing-in-purescript/4787 --- purescript-indentation.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 41d0bc1..51671be 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -649,7 +649,7 @@ indent the current line. This has to be fixed elsewhere." (purescript-indentation-type) (cond ((string= current-token "=") (purescript-indentation-with-starter - (lambda () (purescript-indentation-separated #'purescript-indentation-type "|" "deriving")) + (lambda () (purescript-indentation-separated #'purescript-indentation-type "|" nil)) nil)) ((string= current-token "where") (purescript-indentation-with-starter @@ -998,7 +998,7 @@ indent the current line. This has to be fixed elsewhere." (defun purescript-indentation-peek-token () "Return token starting at point." - (cond ((looking-at "\\(if\\|then\\|else\\|let\\|in\\|ado\\|mdo\\|rec\\|\\(?:[[:word:]]+\\.\\)*do\\|proc\\|case\\|of\\|where\\|module\\|deriving\\|data\\|type\\|newtype\\|class\\|instance\\)\\([^[:alnum:]'_]\\|$\\)") + (cond ((looking-at "\\(if\\|then\\|else\\|let\\|in\\|ado\\|mdo\\|rec\\|\\(?:[[:word:]]+\\.\\)*do\\|proc\\|case\\|of\\|where\\|module\\|data\\|type\\|newtype\\|class\\|instance\\)\\([^[:alnum:]'_]\\|$\\)") (match-string-no-properties 1)) ((looking-at "[][(){}[,;]") (match-string-no-properties 0)) From 2b96f55c52ceeab08945bae94e424408ddabc258 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 10 Dec 2024 21:41:21 +0300 Subject: [PATCH 24/99] Decypher regexp at purescript-indentation-peek-token The 204 characters line full of backslashes and parentheses isn't the most readable code. Replace it with `rx` expression instead, which makes author's intentions much clearer. As can be checked by evaluation, the resulting regexp is exactly the same, barring the "'_" part was moved to the left of [:alnum:]. --- purescript-indentation.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 51671be..cea6137 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -998,7 +998,13 @@ indent the current line. This has to be fixed elsewhere." (defun purescript-indentation-peek-token () "Return token starting at point." - (cond ((looking-at "\\(if\\|then\\|else\\|let\\|in\\|ado\\|mdo\\|rec\\|\\(?:[[:word:]]+\\.\\)*do\\|proc\\|case\\|of\\|where\\|module\\|data\\|type\\|newtype\\|class\\|instance\\)\\([^[:alnum:]'_]\\|$\\)") + (cond ((looking-at + (rx (group + (or "if" "then" "else" "let" "in" "ado" "mdo" "rec" + (seq (0+ (seq (1+ word) ".")) "do") + "proc" "case" "of" "where" "module" "data" "type" "newtype" + "class" "instance")) + (group (or (not (any alnum "'_")) eol)))) (match-string-no-properties 1)) ((looking-at "[][(){}[,;]") (match-string-no-properties 0)) From 246af2eb03b053328b1686675354f328ac70f024 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 11 Dec 2024 01:37:35 +0300 Subject: [PATCH 25/99] Rename haskell tests to purescript --- ...ell-sort-imports-tests.el => purescript-sort-imports-tests.el} | 0 tests/{haskell-str-tests.el => purescript-str-tests.el} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/{haskell-sort-imports-tests.el => purescript-sort-imports-tests.el} (100%) rename tests/{haskell-str-tests.el => purescript-str-tests.el} (100%) diff --git a/tests/haskell-sort-imports-tests.el b/tests/purescript-sort-imports-tests.el similarity index 100% rename from tests/haskell-sort-imports-tests.el rename to tests/purescript-sort-imports-tests.el diff --git a/tests/haskell-str-tests.el b/tests/purescript-str-tests.el similarity index 100% rename from tests/haskell-str-tests.el rename to tests/purescript-str-tests.el From b28d882af84c108ca7b13dd8f9149a28572873bd Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 11 Dec 2024 01:35:21 +0300 Subject: [PATCH 26/99] Fix all "goto-line" is interactive-only warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: tests/purescript-sort-imports-tests.el:31:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. tests/purescript-sort-imports-tests.el:41:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. tests/purescript-sort-imports-tests.el:51:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. tests/purescript-sort-imports-tests.el:61:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. tests/purescript-sort-imports-tests.el:73:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. tests/purescript-sort-imports-tests.el:86:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. tests/purescript-sort-imports-tests.el:99:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. tests/purescript-sort-imports-tests.el:118:14: Warning: ‘goto-line’ is for interactive use only; use ‘forward-line’ instead. --- tests/purescript-sort-imports-tests.el | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/purescript-sort-imports-tests.el b/tests/purescript-sort-imports-tests.el index 7670fb2..e24fec1 100644 --- a/tests/purescript-sort-imports-tests.el +++ b/tests/purescript-sort-imports-tests.el @@ -28,7 +28,7 @@ (ert-deftest single-line () (should (with-temp-buffer (insert "import A\n") - (goto-line 1) + (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) "import A\n")))) @@ -38,7 +38,7 @@ (insert "import A import B ") - (goto-line 1) + (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) "import A @@ -48,7 +48,7 @@ import B (insert "import qualified A import B ") - (goto-line 1) + (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) "import qualified A @@ -58,7 +58,7 @@ import B (insert "import qualified \"mtl\" A import B ") - (goto-line 1) + (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) "import qualified \"mtl\" A @@ -70,7 +70,7 @@ import B (insert "import B import A ") - (goto-line 1) + (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) "import A @@ -83,7 +83,9 @@ import B import B import A ") - (goto-line 2) + ;; test at line 2 + (goto-char (point-min)) + (forward-line 1) (purescript-sort-imports) (string= (buffer-string) "module A where @@ -96,7 +98,9 @@ import B import B import A ") - (goto-line 3) + ;; test at line 3 + (goto-char (point-min)) + (forward-line 2) (purescript-sort-imports) (string= (buffer-string) "module C where @@ -115,7 +119,7 @@ import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L ") - (goto-line 1) + (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) "import Data.Aeson.Encode (encode) From 4d4c7a1ec7fe8c4d06ab33951c5efed143e5f9e6 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 11 Dec 2024 01:43:53 +0300 Subject: [PATCH 27/99] Fix a "missing lexical binding" warning in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: tests/purescript-str-tests.el:1:1: Error: file has no ‘lexical-binding’ directive on its first line --- tests/purescript-str-tests.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/purescript-str-tests.el b/tests/purescript-str-tests.el index 6273fdb..bfd4e88 100644 --- a/tests/purescript-str-tests.el +++ b/tests/purescript-str-tests.el @@ -1,4 +1,4 @@ -;; unit tests for purescript-str.el +;; unit tests for purescript-str.el -*- lexical-binding: t -*- (require 'ert) From eae0f4a5ae176c51191c9c866b6ad0f406f64de6 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 11 Dec 2024 01:31:43 +0300 Subject: [PATCH 28/99] Makefile: compile: make warnings fatal --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 91a391c..b930b15 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ ELCHECKS=$(addprefix check-, $(ELFILES:.el=)) %.elc: %.el @$(BATCH) \ - -f batch-byte-compile $< + --eval "(setq byte-compile-error-on-warn t)" -f batch-byte-compile $< .PHONY: all compile info clean check $(ELCHECKS) elpa package From 02c97485606bca9ece3b2b40c5e436ce0a1ccae4 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 11 Dec 2024 01:33:40 +0300 Subject: [PATCH 29/99] Implement testing with existing tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code that's being removed here made no sense. It is a `check` rule, and it did the following things: 1. For every `.el` file it was searching its `tests.el` counterpart. Which doesn't exist. 2. It was checking the correctness of `declare-function`s. Which would be fine, wasn't it for the fact the project has zero `declare-function`s. 3. It was checking that `ert` exists, which it does on all supported Emacs versions. 4. It was removing .elc files before running the tests. Why? 🤷‍♂️ Replace everything with a single `test` rule which simply loads the test files and runs the tests. Besides being actually useful, this also improves running time as: Initial state | Before | After | Non-compiled | 2.177 | 1.614 | Compiled | 2.182 | 0.340 | --- .github/workflows/ci.yml | 2 +- Makefile | 30 +++++++++--------------------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57381f9..0df5c07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,4 +29,4 @@ jobs: - uses: actions/checkout@v2 - name: Run tests - run: make check + run: make test diff --git a/Makefile b/Makefile index b930b15..e893977 100644 --- a/Makefile +++ b/Makefile @@ -23,43 +23,31 @@ ELFILES = \ purescript-unicode-input-method.el \ purescript-utils.el \ purescript-decl-scan.el \ - purescript-yas.el + purescript-yas.el \ + tests/purescript-sort-imports-tests.el \ + tests/purescript-str-tests.el ELCFILES = $(ELFILES:.el=.elc) AUTOLOADS = purescript-mode-autoloads.el PKG_DIST_FILES = $(ELFILES) logo.svg NEWS purescript-mode.info dir PKG_TAR = purescript-mode-$(VERSION).tar -ELCHECKS=$(addprefix check-, $(ELFILES:.el=)) %.elc: %.el @$(BATCH) \ --eval "(setq byte-compile-error-on-warn t)" -f batch-byte-compile $< -.PHONY: all compile info clean check $(ELCHECKS) elpa package +.PHONY: all compile info clean test elpa package all: compile $(AUTOLOADS) info compile: $(ELCFILES) -$(ELCHECKS): check-%: %.el - @$(BATCH) --eval '(when (check-declare-file "$*.el") (error "check-declare failed"))' - @$(BATCH) \ - --eval "(setq byte-compile-error-on-warn t)" \ - -f batch-byte-compile $*.el - @$(RM) $*.elc - @if [ -f "$(<:%.el=tests/%-tests.el)" ]; then \ - if $(BATCH) --eval "(require 'ert)" 2> /dev/null; then \ - echo; \ - $(BATCH) -l "$(<:%.el=tests/%-tests.el)" -f ert-run-tests-batch-and-exit; \ - else \ - echo "ERT not available, skipping unit tests"; \ - fi; \ - fi - @echo "--" - -check: clean $(ELCHECKS) - @echo "checks passed!" +test: compile + @$(BATCH) -l tests/purescript-sort-imports-tests.elc \ + -l tests/purescript-str-tests.elc \ + -f ert-run-tests-batch-and-exit + @echo "tests passed!" clean: $(RM) $(ELCFILES) $(AUTOLOADS) $(AUTOLOADS:.el=.elc) $(PKG_TAR) purescript-mode.tmp.texi purescript-mode.info dir From ab55d1abf946283f0b8c0b5ea7593faac8c3a518 Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Mon, 30 Dec 2024 00:05:57 +0100 Subject: [PATCH 30/99] Move metadata from purescript-mode-pkg.el to purescript-mode.el --- purescript-mode-pkg.el.in | 2 -- purescript-mode.el | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 purescript-mode-pkg.el.in diff --git a/purescript-mode-pkg.el.in b/purescript-mode-pkg.el.in deleted file mode 100644 index 41ad115..0000000 --- a/purescript-mode-pkg.el.in +++ /dev/null @@ -1,2 +0,0 @@ -(define-package "purescript-mode" "@VERSION@" "A PureScript editing mode" - '((emacs "25.1"))) diff --git a/purescript-mode.el b/purescript-mode.el index f7f9d38..416a510 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -11,6 +11,8 @@ ;; 2014 Tim Dysinger ;; Keywords: faces files PureScript ;; URL: https://github.com/purescript-emacs/purescript-mode +;; Package-Version: @VERSION@ +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. From 8a362fe66696a73d5d96237d30f33252a72b22a8 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 15 Jan 2025 18:38:27 +0300 Subject: [PATCH 31/99] Use font-lock symbols directly instead of fetching from variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The variables are obsolete in Emacs 31.1+ because they introduce confusion (see https://debbugs.gnu.org/cgi/bugreport.cgi?bug=71469 for details). Fixes: purescript-font-lock.el:374:19: Error: ‘font-lock-string-face’ is an obsolete variable (as of 31.1); use the quoted symbol instead: 'font-lock-string-face purescript-font-lock.el:411:5: Error: ‘font-lock-doc-face’ is an obsolete variable (as of 31.1); use the quoted symbol instead: 'font-lock-doc-face purescript-font-lock.el:412:7: Error: ‘font-lock-comment-face’ is an obsolete variable (as of 31.1); use the quoted symbol instead: 'font-lock-comment-face --- purescript-font-lock.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index f642ac6..a9f93ea 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -371,7 +371,7 @@ that should be commented under LaTeX-style literate scripts." (defun purescript-syntactic-face-function (state) "`font-lock-syntactic-face-function' for PureScript." (cond - ((nth 3 state) font-lock-string-face) ; as normal + ((nth 3 state) 'font-lock-string-face) ; as normal ;; Else comment. If it's from syntax table, use default face. ((or (eq 'syntax-table (nth 7 state)) (and (eq purescript-literate 'bird) @@ -408,8 +408,8 @@ that should be commented under LaTeX-style literate scripts." (setq doc (match-beginning 1))) doc))))) (set (make-local-variable 'purescript-font-lock-seen-docstring) t) - font-lock-doc-face) - (t font-lock-comment-face))) + 'font-lock-doc-face) + (t 'font-lock-comment-face))) (defconst purescript-font-lock-keywords (purescript-font-lock-keywords-create nil) From 8fc387f5076ab0e7d4fe9bc787b946d63cbfc4d7 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 11 Dec 2024 13:03:08 +0300 Subject: [PATCH 32/99] Compile .el files at O(1) instead of O(n) The older code was running Emacs separately for each .el file. Change the code so that all .el files are passed at once. This improves build time by x5: * before: 1.272 sec * after: 0.257 sec Also simplify the rule declaration. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e893977..4bfef7f 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ PKG_TAR = purescript-mode-$(VERSION).tar %.elc: %.el @$(BATCH) \ - --eval "(setq byte-compile-error-on-warn t)" -f batch-byte-compile $< + --eval "(setq byte-compile-error-on-warn t)" -f batch-byte-compile $(ELFILES) .PHONY: all compile info clean test elpa package From aa5bb16d66b1c2b42a773245710c85c99deb3417 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 10 Feb 2025 23:18:51 +0300 Subject: [PATCH 33/99] Remove `qualified` keyword from sorting imports Such keyword isn't a thing in Purescript, it has instead syntax `import Foo as Bar`. I also checked VSCode purescript highlight mode, it also doesn't have `qualified` in among its sources. --- purescript-sort-imports.el | 8 +++----- tests/purescript-sort-imports-tests.el | 16 ++++++++-------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/purescript-sort-imports.el b/purescript-sort-imports.el index c635ada..741ef04 100644 --- a/purescript-sort-imports.el +++ b/purescript-sort-imports.el @@ -32,8 +32,7 @@ (defvar purescript-sort-imports-regexp (concat "^import[ ]+" - "\\(qualified \\)?" - "[ ]*\\(\"[^\"]*\" \\)?" + "\\(\"[^\"]*\" \\)?" "[ ]*\\([A-Za-z0-9_.']*.*\\)")) ;;;###autoload @@ -68,9 +67,8 @@ within that region." (defun purescript-sort-imports-normalize (i) "Normalize an import, if possible, so that it can be sorted." - (if (string-match purescript-sort-imports-regexp - i) - (match-string 3 i) + (if (string-match purescript-sort-imports-regexp i) + (match-string 2 i) i)) (defun purescript-sort-imports-collect-imports () diff --git a/tests/purescript-sort-imports-tests.el b/tests/purescript-sort-imports-tests.el index e24fec1..e8025e2 100644 --- a/tests/purescript-sort-imports-tests.el +++ b/tests/purescript-sort-imports-tests.el @@ -45,23 +45,23 @@ import B import B "))) (should (with-temp-buffer - (insert "import qualified A + (insert "import A (A, B, C) import B ") (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) - "import qualified A + "import A (A, B, C) import B "))) (should (with-temp-buffer - (insert "import qualified \"mtl\" A + (insert "import A (mtl) import B ") (goto-char (point-min)) (purescript-sort-imports) (string= (buffer-string) - "import qualified \"mtl\" A + "import A (mtl) import B ")))) @@ -116,8 +116,8 @@ import Data.Aeson.Types import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json') -import qualified Data.ByteString as B -import qualified Data.ByteString.Lazy as L +import Data.ByteString as B +import Data.ByteString.Lazy as L ") (goto-char (point-min)) (purescript-sort-imports) @@ -127,8 +127,8 @@ import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json') import Data.Aeson.Types -import qualified Data.ByteString as B -import qualified Data.ByteString.Lazy as L +import Data.ByteString as B +import Data.ByteString.Lazy as L ")))) (provide 'purescript-sort-imports-tests) From 0f832dadaa991904a4e2e77480ec748656cb21c6 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 10 Feb 2025 23:33:30 +0300 Subject: [PATCH 34/99] tests: only use `should` for specific assertions This improves debuggability of fails, because tests would only show the part that failed. There's no reason to wrap full code blocks to `should` because their execution may only exit past `should` if exception is thrown, which would be caught by `ert` anyway. --- tests/purescript-sort-imports-tests.el | 94 +++++++++++++------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/tests/purescript-sort-imports-tests.el b/tests/purescript-sort-imports-tests.el index e8025e2..fd5de6b 100644 --- a/tests/purescript-sort-imports-tests.el +++ b/tests/purescript-sort-imports-tests.el @@ -21,88 +21,88 @@ (require 'purescript-sort-imports) (ert-deftest empty-buffer () - (should (with-temp-buffer - (purescript-sort-imports) - t))) + (with-temp-buffer + (purescript-sort-imports) + t)) (ert-deftest single-line () - (should (with-temp-buffer - (insert "import A\n") - (goto-char (point-min)) - (purescript-sort-imports) - (string= (buffer-string) + (with-temp-buffer + (insert "import A\n") + (goto-char (point-min)) + (purescript-sort-imports) + (should (string= (buffer-string) "import A\n")))) (ert-deftest two-idem () - (should (with-temp-buffer - (insert "import A + (with-temp-buffer + (insert "import A import B ") - (goto-char (point-min)) - (purescript-sort-imports) - (string= (buffer-string) + (goto-char (point-min)) + (purescript-sort-imports) + (should (string= (buffer-string) "import A import B "))) - (should (with-temp-buffer - (insert "import A (A, B, C) + (with-temp-buffer + (insert "import A (A, B, C) import B ") - (goto-char (point-min)) - (purescript-sort-imports) - (string= (buffer-string) + (goto-char (point-min)) + (purescript-sort-imports) + (should (string= (buffer-string) "import A (A, B, C) import B "))) - (should (with-temp-buffer - (insert "import A (mtl) + (with-temp-buffer + (insert "import A (mtl) import B ") - (goto-char (point-min)) - (purescript-sort-imports) - (string= (buffer-string) + (goto-char (point-min)) + (purescript-sort-imports) + (should (string= (buffer-string) "import A (mtl) import B ")))) (ert-deftest two-rev () - (should (with-temp-buffer - (insert "import B + (with-temp-buffer + (insert "import B import A ") - (goto-char (point-min)) - (purescript-sort-imports) - (string= (buffer-string) + (goto-char (point-min)) + (purescript-sort-imports) + (should (string= (buffer-string) "import A import B ")))) (ert-deftest file-structure () - (should (with-temp-buffer - (insert "module A where + (with-temp-buffer + (insert "module A where import B import A ") - ;; test at line 2 - (goto-char (point-min)) - (forward-line 1) - (purescript-sort-imports) - (string= (buffer-string) + ;; test at line 2 + (goto-char (point-min)) + (forward-line 1) + (purescript-sort-imports) + (should (string= (buffer-string) "module A where import A import B "))) - (should (with-temp-buffer - (insert "module C where + (with-temp-buffer + (insert "module C where import B import A ") - ;; test at line 3 - (goto-char (point-min)) - (forward-line 2) - (purescript-sort-imports) - (string= (buffer-string) + ;; test at line 3 + (goto-char (point-min)) + (forward-line 2) + (purescript-sort-imports) + (should (string= (buffer-string) "module C where import A @@ -110,8 +110,8 @@ import B ")))) (ert-deftest bos-270 () - (should (with-temp-buffer - (insert "import Data.Aeson.Encode (encode) + (with-temp-buffer + (insert "import Data.Aeson.Encode (encode) import Data.Aeson.Types import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, @@ -119,9 +119,9 @@ import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, import Data.ByteString as B import Data.ByteString.Lazy as L ") - (goto-char (point-min)) - (purescript-sort-imports) - (string= (buffer-string) + (goto-char (point-min)) + (purescript-sort-imports) + (should (string= (buffer-string) "import Data.Aeson.Encode (encode) import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, From 4c2d1883c2a936edb1a704dc5570315e76a27ef6 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 10 Feb 2025 23:43:03 +0300 Subject: [PATCH 35/99] Don't "autoload" purescript-sort-imports The function will be brought into the scope by purescript-mode by virtue of having a `(require 'purescript-sort-imports)`. No point additionally declaring it as autoload. --- purescript-sort-imports.el | 1 - 1 file changed, 1 deletion(-) diff --git a/purescript-sort-imports.el b/purescript-sort-imports.el index 741ef04..796eee8 100644 --- a/purescript-sort-imports.el +++ b/purescript-sort-imports.el @@ -35,7 +35,6 @@ "\\(\"[^\"]*\" \\)?" "[ ]*\\([A-Za-z0-9_.']*.*\\)")) -;;;###autoload (defun purescript-sort-imports () "Sort the import list at point. It sorts the current group i.e. an import list separated by blank lines on either side. From bde378f6289390b98836a180f7cab33dbe8efbde Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 18 Feb 2025 22:52:40 +0300 Subject: [PATCH 36/99] ci: remove minor releases from the matrix No point in testing minor Emacs releases, because they have no major features anyway, fixes only. E.g. given Emacs 25: 25.1, 25.2 and 25.3 are only different in amount of fixes. It isn't expected that something may break between these releases. So there's not much point in running tests on all of them. This commit removes most minor Emacs versions and only leaves in the initial release for each Emacs major version. It was brought up here before https://github.com/purescript-emacs/purescript-mode/pull/33#issuecomment-2649211246 so far to no opposition. --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0df5c07..b0f3cdf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,13 +13,8 @@ jobs: matrix: emacs_version: - 25.1 - - 25.2 - - 25.3 - 26.1 - - 26.2 - - 26.3 - 27.1 - - 27.2 - 28.1 - snapshot steps: From 7ec2f4dce30f4e5bc4ae2262c75357b062f7d5dd Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 18 Feb 2025 21:11:00 +0300 Subject: [PATCH 37/99] Test PureScript indentation --- Makefile | 2 + tests/purescript-indentation-tests.el | 240 ++++++++++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 tests/purescript-indentation-tests.el diff --git a/Makefile b/Makefile index 4bfef7f..33a6dfa 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ ELFILES = \ purescript-decl-scan.el \ purescript-yas.el \ tests/purescript-sort-imports-tests.el \ + tests/purescript-indentation-tests.el \ tests/purescript-str-tests.el ELCFILES = $(ELFILES:.el=.elc) @@ -46,6 +47,7 @@ compile: $(ELCFILES) test: compile @$(BATCH) -l tests/purescript-sort-imports-tests.elc \ -l tests/purescript-str-tests.elc \ + -l tests/purescript-indentation-tests.elc \ -f ert-run-tests-batch-and-exit @echo "tests passed!" diff --git a/tests/purescript-indentation-tests.el b/tests/purescript-indentation-tests.el new file mode 100644 index 0000000..f61c90d --- /dev/null +++ b/tests/purescript-indentation-tests.el @@ -0,0 +1,240 @@ +;;; purescript-indentation-tests.el --- Unit tests for purescript indentation -*- lexical-binding: t -*- + +;; Copyright (c) 2025 Konstantin Kharlamov. All rights reserved. + +;; This file 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, or (at your option) +;; any later version. + +;; This file 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 . + +;;; Code: + +(require 'ert) +(require 'purescript-mode) +(require 'purescript-indentation) + +(defun purescript-test-indentation (before after &optional start-line) + (with-temp-buffer + (insert before) + (purescript-mode) + (turn-on-purescript-indentation) + (indent-region (if start-line start-line (point-min)) + (point-max)) + (should (string= after (buffer-string))))) + +(ert-deftest newtype-comma-first () + (purescript-test-indentation " +newtype Foo = Foo { field1 :: MyType +, field2 :: Int +, field3 :: HashMap ParType Foo }" + +" +newtype Foo = Foo { field1 :: MyType + , field2 :: Int + , field3 :: HashMap ParType Foo }")) + +(ert-deftest newtype-comma-end () + (purescript-test-indentation " +newtype Foo = Foo { field1 :: MyType, +field2 :: Int, +field3 :: HashMap ParType Foo }" + +" +newtype Foo = Foo { field1 :: MyType, + field2 :: Int, + field3 :: HashMap ParType Foo }")) + +(ert-deftest data-bar-first () + (purescript-test-indentation " +data Foo = Foo1 Bar +| Foo2 Bar2 +| Foo3 Unit" + +" +data Foo = Foo1 Bar + | Foo2 Bar2 + | Foo3 Unit")) + +(ert-deftest data-bar-end () + (purescript-test-indentation " +data Foo = Foo1 Bar | +Foo2 Bar2 | +Foo3 Unit" + +" +data Foo = Foo1 Bar | + Foo2 Bar2 | + Foo3 Unit")) + +(ert-deftest imports-zero-indented () + :expected-result :failed + (purescript-test-indentation " +module MyModule where + +import Prelude + + import Data.Array (many) + import Data.Array as Array + import Data.Either (Either(..))" + +" +module MyModule where + +import Prelude + +import Data.Array (many) +import Data.Array as Array +import Data.Either (Either(..))")) + +(ert-deftest imports-indented-forward () + "PureScript allows for imports to have indentation, but the + indentation must be the same. In this test we skip first indented + import, and test that further lines inherit indentation level." + :expected-result :failed + (purescript-test-indentation " +module MyModule where + + import Prelude + +import Data.Array (many) +import Data.Array as Array +import Data.Either (Either(..))" + +" +module MyModule where + + import Prelude + + import Data.Array (many) + import Data.Array as Array + import Data.Either (Either(..))" + 6)) + +(ert-deftest imports-qualified-newline-comma-first () + :expected-result :failed + (purescript-test-indentation " +import Data.List.NonEmpty (NonEmptyList) +import Data.Maybe (Maybe(..) +, fromMaybe)" + +" +import Data.List.NonEmpty (NonEmptyList) +import Data.Maybe ( Maybe(..) + , fromMaybe)")) + +(ert-deftest imports-qualified-newline-comma-end () + :expected-result :failed + (purescript-test-indentation " +import Data.List.NonEmpty (NonEmptyList) +import Data.Maybe (Maybe(..), +fromMaybe)" + +" +import Data.List.NonEmpty (NonEmptyList) +import Data.Maybe (Maybe(..), + fromMaybe)")) + +(ert-deftest do-impl () + (purescript-test-indentation " +main = do +pure unit" + +" +main = do + pure unit")) + +(ert-deftest let-bindings () + :expected-result :failed + (purescript-test-indentation " +main = do + let foo = 1 + bar = 2 + let + buzz = 1 + fuzz = 2 +pure unit" + +" +main = do + let foo = 1 + bar = 2 + let + buzz = 1 + fuzz = 2 + pure unit")) + +(ert-deftest module-exports-list () + :expected-result :failed + (purescript-test-indentation " +module MyModule ( class A +, b, c +, d) where" + +" +module MyModule ( class A + , b, c + , d) where")) + +(ert-deftest module-exports-next-line () + "Parentheses should get indented to the mode indentation size" + :expected-result :failed + (purescript-test-indentation " +module MyModule + (class A, b, c, d) where" + +" +module MyModule + (class A, b, c, d) where")) + +(ert-deftest keyword-record-values () + "PureScript allows keywords to be part of a Record declaration" + :expected-result :failed + (purescript-test-indentation " +type MyRec = { data :: Number +, where :: Number +, instance :: Number +}" + +" +type MyRec = { data :: Number + , where :: Number + , instance :: Number + }")) + +(ert-deftest func-with-do () + :expected-result :failed + (purescript-test-indentation " +foo :: Foo +foo = do + pure unit" + +" +foo :: Foo +foo = do + pure unit")) + +(ert-deftest do-bindings () + :expected-result :failed + (purescript-test-indentation " +foo :: Foo +foo = do +_ <- something +identifier :: Array String <- function call +_ <- another call +pure unit" + +" +foo :: Foo +foo = do + _ <- something + identifier :: Array String <- function call + _ <- another call + pure unit")) From 9b136aed2239e52ad85ec6c45e1d748814536a42 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 18 Feb 2025 23:05:33 +0300 Subject: [PATCH 38/99] purescript-indentation: remove Emacs 21 work around We don't support Emacs 21 (it's very old), so no point in keeping it. --- purescript-indentation.el | 7 ------- 1 file changed, 7 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index cea6137..33bf8b2 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -111,13 +111,6 @@ :group 'purescript-indentation) -;; Avoid a global bogus definition (which the original run-time -;; `defun' made), and support Emacs 21 without the syntax.el add-on. -(eval-when-compile - (unless (fboundp 'syntax-ppss) - (defsubst syntax-ppss (&rest pos) - (parse-partial-sexp (point-min) (or pos (point)))))) - (defconst purescript-indentation-mode-map (let ((keymap (make-sparse-keymap))) (define-key keymap [?\r] 'purescript-newline-and-indent) From e0108144ac50296d761376d194b83db6385b27a7 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 19 Feb 2025 05:12:18 +0300 Subject: [PATCH 39/99] Add syntax highlight tests --- Makefile | 2 + tests/purescript-font-lock-tests.el | 98 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 tests/purescript-font-lock-tests.el diff --git a/Makefile b/Makefile index 33a6dfa..354cc21 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ ELFILES = \ purescript-yas.el \ tests/purescript-sort-imports-tests.el \ tests/purescript-indentation-tests.el \ + tests/purescript-font-lock-tests.el \ tests/purescript-str-tests.el ELCFILES = $(ELFILES:.el=.elc) @@ -48,6 +49,7 @@ test: compile @$(BATCH) -l tests/purescript-sort-imports-tests.elc \ -l tests/purescript-str-tests.elc \ -l tests/purescript-indentation-tests.elc \ + -l tests/purescript-font-lock-tests.elc \ -f ert-run-tests-batch-and-exit @echo "tests passed!" diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el new file mode 100644 index 0000000..e9d3865 --- /dev/null +++ b/tests/purescript-font-lock-tests.el @@ -0,0 +1,98 @@ +;;; purescript-font-lock-tests.el --- Unit tests for purescript font-lock -*- lexical-binding: t -*- + +;; Copyright (c) 2025 Konstantin Kharlamov. All rights reserved. + +;; This file 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, or (at your option) +;; any later version. + +;; This file 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 . + +;;; Code: + +(require 'ert) +(require 'purescript-mode) + +(defun purescript-test-ranges (text ranges-list) + (with-temp-buffer + (insert text) + (purescript-mode) + (font-lock-ensure) + (let ((ret + (catch 'fail + (dolist (range ranges-list) + (let ((begin (nth 0 range)) + (end (nth 1 range)) + (face-expected (nth 2 range))) + (dolist (pos (number-sequence begin end)) + (let ((face-found (get-char-property pos 'face))) + (when (not (eq face-found face-expected)) + (throw 'fail `(,begin ,end ,face-expected ,face-found ,pos))))))) + nil))) + (when ret + (message "Range [%d:%d] has face %s (expected %s) at %d" + (nth 0 ret) (nth 1 ret) (nth 3 ret) (nth 2 ret) (nth 4 ret)) + (should-not ret))))) + +(ert-deftest imports () + (purescript-test-ranges + "import Data.Array (many) +import Data.Array as Array +import Data.Either (Either(..)) +" '((1 6 font-lock-keyword-face) + (8 17 font-lock-type-face) + (26 31 font-lock-keyword-face) + (33 42 font-lock-type-face) + (44 45 font-lock-keyword-face) + (47 51 font-lock-type-face) + (53 58 font-lock-keyword-face) + (60 70 font-lock-type-face) + (73 78 font-lock-type-face) + (80 81 font-lock-variable-name-face)))) + +(ert-deftest string () + (purescript-test-ranges + "foo = \"hello\"" + '((1 3 font-lock-function-name-face) + (5 5 font-lock-variable-name-face) + (7 13 font-lock-string-face)))) + +(ert-deftest multiline-string () + (purescript-test-ranges + "foo = \"\"\" +hello +\"\"\" +" + '((1 3 font-lock-function-name-face) + (5 5 font-lock-variable-name-face) + (7 19 font-lock-string-face)))) + +(ert-deftest multiline-string-with-hash () + :expected-result :failed + (purescript-test-ranges + "foo = \"\"\" +# a string with hashtag + # another # one +\"\"\" +" + '((1 3 font-lock-function-name-face) + (5 5 font-lock-variable-name-face) + (7 55 font-lock-string-face)))) + +(ert-deftest multiline-string-with-embedded-strings () + :expected-result :failed + (purescript-test-ranges + "foo = \"\"\" +this = \"still a string\" +\"\"\" +" + '((1 3 font-lock-function-name-face) + (5 5 font-lock-variable-name-face) + (7 37 font-lock-string-face)))) From f364b21b8bbc9799cae794927f0aea52f3706709 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 19 Feb 2025 00:18:33 +0300 Subject: [PATCH 40/99] Fix imports getting unsolicited indentation When pressing RET after an import, the line gets indented even though it shouldn't. Fix that. --- purescript-indentation.el | 2 +- tests/purescript-indentation-tests.el | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 33bf8b2..a48a726 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -993,7 +993,7 @@ indent the current line. This has to be fixed elsewhere." "Return token starting at point." (cond ((looking-at (rx (group - (or "if" "then" "else" "let" "in" "ado" "mdo" "rec" + (or "if" "then" "else" "let" "in" "ado" "mdo" "rec" "import" (seq (0+ (seq (1+ word) ".")) "do") "proc" "case" "of" "where" "module" "data" "type" "newtype" "class" "instance")) diff --git a/tests/purescript-indentation-tests.el b/tests/purescript-indentation-tests.el index f61c90d..f2dac73 100644 --- a/tests/purescript-indentation-tests.el +++ b/tests/purescript-indentation-tests.el @@ -75,7 +75,6 @@ data Foo = Foo1 Bar | Foo3 Unit")) (ert-deftest imports-zero-indented () - :expected-result :failed (purescript-test-indentation " module MyModule where From 493647044e9ae25060595c881ef3dafc4a06a61b Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 02:49:52 +0300 Subject: [PATCH 41/99] Extend string tests to cover comment constructions --- tests/purescript-font-lock-tests.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index e9d3865..d10fa52 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -80,11 +80,14 @@ hello "foo = \"\"\" # a string with hashtag # another # one +-- not a comment -- +-- | not a comment +{- not a comment -} \"\"\" " '((1 3 font-lock-function-name-face) (5 5 font-lock-variable-name-face) - (7 55 font-lock-string-face)))) + (7 114 font-lock-string-face)))) (ert-deftest multiline-string-with-embedded-strings () :expected-result :failed From e0e33fd3b18d1515050fdb84f630e9a97ba46efb Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 22 Feb 2025 11:16:55 +0300 Subject: [PATCH 42/99] Test comments highlighting --- tests/purescript-font-lock-tests.el | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index d10fa52..798f7ad 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -99,3 +99,58 @@ this = \"still a string\" '((1 3 font-lock-function-name-face) (5 5 font-lock-variable-name-face) (7 37 font-lock-string-face)))) + +(ert-deftest docs-bar-comment-different-spacings () + (purescript-test-ranges + "-- | Docs comment space +-- | Docs comment many spaces +" + '((1 57 font-lock-doc-face)))) + +(ert-deftest docs-bar-comment-continuation () + "Acc. to +https://github.com/purescript/documentation/blob/master/language/Syntax.md +PureScript explicitly doesn't support Haskell-style docs continuation +where vertical bar is omitted" + :expected-result :failed + (purescript-test-ranges + "-- | Docs start +-- continue +" + '((1 16 font-lock-doc-face) + (17 19 font-lock-comment-delimiter-face) + (20 28 font-lock-comment-face)))) + +(ert-deftest docs-cap-comment-different-spacings () + (purescript-test-ranges + "-- ^ Docs comment space +-- ^ Docs comment many spaces +" + '((1 57 font-lock-doc-face)))) + +(ert-deftest multiline-comment () + (purescript-test-ranges + "{- +multiline comment +-- | not a doc +--| not a doc +still comment +-} +noncomment +{--} +noncomment +" + '((1 64 font-lock-comment-face) + (65 66 font-lock-comment-delimiter-face) + (67 78 nil) + (79 80 font-lock-comment-face) + (81 82 font-lock-comment-delimiter-face) + (83 93 nil)))) + +(ert-deftest multiline-comment-w-delimiter-inside () + :expected-result :failed + (purescript-test-ranges + "{- {-{- -} noncomment" + '((1 6 font-lock-comment-face) + (7 10 font-lock-comment-delimiter-face) + (11 21 nil)))) From bd3f3c6799df20106403d1b7c36758fe87a724b2 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 02:38:31 +0300 Subject: [PATCH 43/99] Don't consider a comment after docs-comment a documentation As described in the test and the commentary, PureScript doesn't consider a "no-bar" comment that follows documentation part of the documentation. It is an explicitly documented behavior that is different from Haskell. --- purescript-font-lock.el | 32 +++++++---------------------- tests/purescript-font-lock-tests.el | 3 +-- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index a9f93ea..2b21ae7 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -363,9 +363,6 @@ that should be commented under LaTeX-style literate scripts." :type 'boolean :group 'purescript) -(defvar purescript-font-lock-seen-docstring nil) -(make-variable-buffer-local 'purescript-font-lock-seen-docstring) - (defvar purescript-literate) (defun purescript-syntactic-face-function (state) @@ -383,31 +380,16 @@ that should be commented under LaTeX-style literate scripts." ;; b) {-^ ... -} ;; c) -- | ... ;; d) -- ^ ... - ;; e) -- ... - ;; Where `e' is the tricky one: it is only a docstring comment if it - ;; follows immediately another docstring comment. Even an empty line - ;; breaks such a sequence of docstring comments. It is not clear if `e' - ;; can follow any other case, so I interpreted it as following only cases - ;; c,d,e (not a or b). In any case, this `e' is expensive since it - ;; requires extra work for each and every non-docstring comment, so I only - ;; go through the more expensive check if we've already seen a docstring - ;; comment in the buffer. + + ;; Worth pointing out purescript opted out of ability to continue + ;; docs-comment by omitting an empty line like in Haskell, see: + ;; https://github.com/purescript/documentation/blob/master/language/Syntax.md + ;; IOW, given a `-- | foo' line followed by `-- bar' line, the latter is a + ;; plain comment. ((and purescript-font-lock-docstrings (save-excursion (goto-char (nth 8 state)) - (or (looking-at "\\(-- \\|{-\\)[ \\t]*[|^]") - (and purescript-font-lock-seen-docstring - (looking-at "-- ") - (let ((doc nil) - pos) - (while (and (not doc) - (setq pos (line-beginning-position)) - (forward-comment -1) - (eq (line-beginning-position 2) pos) - (looking-at "--\\( [|^]\\)?")) - (setq doc (match-beginning 1))) - doc))))) - (set (make-local-variable 'purescript-font-lock-seen-docstring) t) + (looking-at "\\(-- \\|{-\\)[ \\t]*[|^]"))) 'font-lock-doc-face) (t 'font-lock-comment-face))) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 798f7ad..b9ea38d 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -102,7 +102,7 @@ this = \"still a string\" (ert-deftest docs-bar-comment-different-spacings () (purescript-test-ranges - "-- | Docs comment space + "-- | Docs comment 1 space -- | Docs comment many spaces " '((1 57 font-lock-doc-face)))) @@ -112,7 +112,6 @@ this = \"still a string\" https://github.com/purescript/documentation/blob/master/language/Syntax.md PureScript explicitly doesn't support Haskell-style docs continuation where vertical bar is omitted" - :expected-result :failed (purescript-test-ranges "-- | Docs start -- continue From 31568404643e253041d717c3dcb395a32328bf79 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 02:57:20 +0300 Subject: [PATCH 44/99] Remove code that depended on lack of font-lock-syntactic-keywords The variable exists since Emacs 21 at least, so this check serves no purpose. --- purescript-font-lock.el | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 2b21ae7..f93d05e 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -262,17 +262,6 @@ Returns keywords suitable for `font-lock-keywords'." (,sym 0 (if (eq (char-after (match-beginning 0)) ?:) purescript-constructor-face purescript-operator-face)))) - (unless (boundp 'font-lock-syntactic-keywords) - (cl-case literate - (bird - (setq keywords - `(("^[^>\n].*$" 0 purescript-comment-face t) - ,@keywords - ("^>" 0 purescript-default-face t)))) - ((latex tex) - (setq keywords - `((purescript-fl-latex-comments 0 'font-lock-comment-face t) - ,@keywords))))) keywords)) ;; The next three aren't used in Emacs 21. From 58fce7c4b3d1cc9f6469b555fd126ee792e2f8f5 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 05:10:29 +0300 Subject: [PATCH 45/99] Add `type` highlight test --- tests/purescript-font-lock-tests.el | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index b9ea38d..5dbf422 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -153,3 +153,19 @@ noncomment '((1 6 font-lock-comment-face) (7 10 font-lock-comment-delimiter-face) (11 21 nil)))) + +(ert-deftest type-with-typenames-and--> () + (purescript-test-ranges + "type Component props = Effect (props -> JSX)" + '((1 4 font-lock-keyword-face) + (5 5 nil) + (6 14 font-lock-type-face) + (15 21 nil) + (22 22 font-lock-variable-name-face) + (23 23 nil) + (24 29 font-lock-type-face) + (30 37 nil) + (38 39 font-lock-variable-name-face) + (40 40 nil) + (41 43 font-lock-type-face) + (44 45 nil)))) From 413f56a58ae71f09f924fd963685c2af5f15a19a Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 13:28:38 +0300 Subject: [PATCH 46/99] Factor out `(purescript-font-lock-defaults-create)` block --- purescript-mode.el | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index 416a510..dd18942 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -322,16 +322,7 @@ see documentation for that variable for more details." (set (make-local-variable 'comment-end-skip) "[ \t]*\\(-}\\|\\s>\\)") (set (make-local-variable 'parse-sexp-ignore-comments) nil) (set (make-local-variable 'indent-line-function) 'purescript-mode-suggest-indent-choice) - ;; Set things up for font-lock. - (set (make-local-variable 'font-lock-defaults) - '(purescript-font-lock-choose-keywords - nil nil ((?\' . "w") (?_ . "w")) nil - (font-lock-syntactic-keywords - . purescript-font-lock-choose-syntactic-keywords) - (font-lock-syntactic-face-function - . purescript-syntactic-face-function) - ;; Get help from font-lock-syntactic-keywords. - (parse-sexp-lookup-properties . t))) + (purescript-font-lock-defaults-create) ; set things up for font-lock. ;; PureScript's layout rules mean that TABs have to be handled with extra care. ;; The safer option is to avoid TABs. The second best is to make sure ;; TABs stops are 8 chars apart, as mandated by the PureScript Report. --Stef From f51a214c28999723fd295935ce84a789cfc21261 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 14:41:03 +0300 Subject: [PATCH 47/99] Restore `module` in non-toplevel and test that --- purescript-font-lock.el | 4 ++-- tests/purescript-font-lock-tests.el | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index f93d05e..2757a09 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -177,7 +177,7 @@ Returns keywords suitable for `font-lock-keywords'." ;; record fields or other identifiers. (toplevel-keywords (rx line-start (zero-or-more whitespace) - (group (or "type" "module" "import" "data" "class" "newtype" + (group (or "type" "import" "data" "class" "newtype" "instance" "derive") word-end))) ;; Reserved identifiers @@ -186,7 +186,7 @@ Returns keywords suitable for `font-lock-keywords'." ;; spec syntax, but they are not reserved. ;; `_' can go in here since it has temporary word syntax. (regexp-opt - '("ado" "case" "do" "else" "if" "in" "infix" + '("ado" "case" "do" "else" "if" "in" "infix" "module" "infixl" "infixr" "let" "of" "then" "where" "_") 'words)) ;; Top-level declarations diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 5dbf422..76cfa08 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -169,3 +169,25 @@ noncomment (40 40 nil) (41 43 font-lock-type-face) (44 45 nil)))) + +(ert-deftest module-in-different-locations () + (purescript-test-ranges + "module React.Basic.Hooks ( Component, module React.Basic + , module Data.Tuple.Nested ) where +" + '((1 6 font-lock-keyword-face) + (7 7 nil) + (8 24 font-lock-type-face) + (25 27 nil) + (28 36 font-lock-type-face) + (37 38 nil) + (39 44 font-lock-keyword-face) + (45 45 nil) + (46 56 font-lock-type-face) + (57 84 nil) + (85 90 font-lock-keyword-face) + (91 91 nil) + (92 108 font-lock-type-face) + (109 111 nil) + (112 116 font-lock-keyword-face) + (117 117 nil)))) From 81d0cbc1b2548d0f9885ea5ee91574bc2476b261 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 14:54:37 +0300 Subject: [PATCH 48/99] Add test for do + qualified do --- tests/purescript-font-lock-tests.el | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 76cfa08..8cbe9d9 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -191,3 +191,59 @@ noncomment (109 111 nil) (112 116 font-lock-keyword-face) (117 117 nil)))) + +(ert-deftest func-decl-w-do-and-qualified-do () + (purescript-test-ranges + "mkMyComponent :: Component {} +mkMyComponent = do + modalComp :: (NodeRef -> JSX) <- mkModal + component \"mkMyComponent\" \\_ -> React.do + dialogRef :: NodeRef <- newNodeRef + pure $ R.label_ [] +" + '((1 13 font-lock-function-name-face) + (14 14 nil) + (15 16 font-lock-variable-name-face) + (17 17 nil) + (18 26 font-lock-type-face) + (27 30 nil) + (31 43 font-lock-function-name-face) + (44 44 nil) + (45 45 font-lock-variable-name-face) + (46 46 nil) + (47 48 font-lock-keyword-face) + (49 61 nil) + (62 63 font-lock-variable-name-face) + (64 65 nil) + (66 72 font-lock-type-face) + (73 73 nil) + (74 75 font-lock-variable-name-face) + (76 76 nil) + (77 79 font-lock-type-face) + (80 81 nil) + (82 83 font-lock-variable-name-face) + (84 104 nil) + (105 119 font-lock-string-face) + (120 120 nil) + (121 121 font-lock-variable-name-face) + (122 122 font-lock-keyword-face) + (123 123 nil) + (124 125 font-lock-variable-name-face) + (126 126 nil) + (127 131 font-lock-type-face) + (132 132 font-lock-variable-name-face) + (133 134 font-lock-keyword-face) + (135 149 nil) + (150 151 font-lock-variable-name-face) + (152 152 nil) + (153 159 font-lock-type-face) + (160 160 nil) + (161 162 font-lock-variable-name-face) + (163 181 nil) + (182 182 font-lock-variable-name-face) + (183 183 nil) + (184 184 font-lock-type-face) + (185 185 font-lock-variable-name-face) + (186 192 nil) + (193 194 font-lock-type-face) + (195 195 nil)))) From 09298c417bac81ac9ca8b529ab3387e1ffb68d3f Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 20 Feb 2025 19:41:07 +0300 Subject: [PATCH 49/99] Don't highlight preprocessor syntax Purescript has no preprocessor, this is a Haskell legacy. This fixes highlight in multiline strings. --- purescript-font-lock.el | 2 -- tests/purescript-font-lock-tests.el | 1 - 2 files changed, 3 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 2757a09..692ae46 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -211,8 +211,6 @@ Returns keywords suitable for `font-lock-keywords'." (setq keywords `(;; NOTICE the ordering below is significant ;; - ("^#.*$" 0 'font-lock-preprocessor-face t) - (,toplevel-keywords 1 (symbol-value 'purescript-keyword-face)) (,reservedid 1 (symbol-value 'purescript-keyword-face)) (,reservedsym 1 (symbol-value 'purescript-operator-face)) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 8cbe9d9..d24725a 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -75,7 +75,6 @@ hello (7 19 font-lock-string-face)))) (ert-deftest multiline-string-with-hash () - :expected-result :failed (purescript-test-ranges "foo = \"\"\" # a string with hashtag From 12c4d60f4f28107e12f5615f01455d74256358e7 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 25 Feb 2025 01:46:33 +0300 Subject: [PATCH 50/99] Limit multiline-comment test to Emacs 28+ --- tests/purescript-font-lock-tests.el | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index d24725a..984d33a 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -126,8 +126,10 @@ where vertical bar is omitted" " '((1 57 font-lock-doc-face)))) -(ert-deftest multiline-comment () - (purescript-test-ranges +;; For some unknown reason this fails on older Emacses +(when (>= emacs-major-version 28) + (ert-deftest multiline-comment () + (purescript-test-ranges "{- multiline comment -- | not a doc @@ -138,12 +140,12 @@ noncomment {--} noncomment " - '((1 64 font-lock-comment-face) - (65 66 font-lock-comment-delimiter-face) - (67 78 nil) - (79 80 font-lock-comment-face) - (81 82 font-lock-comment-delimiter-face) - (83 93 nil)))) + '((1 64 font-lock-comment-face) + (65 66 font-lock-comment-delimiter-face) + (67 78 nil) + (79 80 font-lock-comment-face) + (81 82 font-lock-comment-delimiter-face) + (83 93 nil))))) (ert-deftest multiline-comment-w-delimiter-inside () :expected-result :failed From 117a6605681e294916fa1fe32f97ee2346ec6652 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 23 Feb 2025 12:39:37 +0300 Subject: [PATCH 51/99] Remove turn-on-purescript-font-lock and turn-off-purescript-font-lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions provide no useful cases because font-locking is enabled by default and can be disabled by turning off font-lock (which the "turn-off" function is a wrapper over). At the same time, the function constitutes huge chunk of the code and comes up while trying to figure where things are called from. Basically, the functions are just duplicating the functional, and I'm hoping they have no users. Turns out also, the function removal was attempted in 0a9580da, however… I am not exactly sure what went wrong but the author only posted the NEWS entry about the functions being removed, but made no chages regarding them. --- purescript-font-lock.el | 95 +++++++++-------------------------------- 1 file changed, 20 insertions(+), 75 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 692ae46..1e9897f 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -31,20 +31,32 @@ ;; functions, etc. Supports full PureScript 1.4 as well as LaTeX- and ;; Bird-style literate scripts. ;; -;; Installation: +;; Customisation: ;; -;; To turn font locking on for all PureScript buffers under the PureScript -;; mode of Moss&Thorn, add this to .emacs: +;; Two levels of fontification are defined: level one (the default) +;; and level two (more colour). The former does not colour operators. +;; Use the variable `font-lock-maximum-decoration' to choose +;; non-default levels of fontification. For example, adding this to +;; .emacs: ;; -;; (add-hook 'purescript-mode-hook 'turn-on-purescript-font-lock) +;; (setq font-lock-maximum-decoration \\='((purescript-mode . 2) (t . 0))) ;; -;; Otherwise, call `turn-on-purescript-font-lock'. +;; uses level two fontification for `purescript-mode' and default level for all +;; other modes. See documentation on this variable for further details. ;; +;; To alter an attribute of a face, add a hook. For example, to change the +;; foreground colour of comments to brown, add the following line to .emacs: ;; -;; Customisation: +;; (add-hook \\='purescript-font-lock-hook +;; (lambda () +;; (set-face-foreground \\='purescript-comment-face \"brown\"))) +;; +;; Note that the colours available vary from system to system. To see what +;; colours are available on your system, call `list-colors-display' from emacs. ;; -;; The colours and level of font locking may be customised. See the -;; documentation on `turn-on-purescript-font-lock' for more details. +;; Bird-style literate PureScript scripts are supported: If the value of +;; `purescript-literate-bird-style' (automatically set by the PureScript mode of +;; Moss&Thorn) is non-nil, a Bird-style literate script is assumed. ;; ;; Present Limitations/Future Work (contributions are most welcome!): ;; @@ -417,73 +429,6 @@ that should be commented under LaTeX-style literate scripts." ;; Get help from font-lock-syntactic-keywords. (parse-sexp-lookup-properties . t)))) -;; The main functions. -(defun turn-on-purescript-font-lock () - "Turns on font locking in current buffer for PureScript 1.4 scripts. - -Changes the current buffer\\='s `font-lock-defaults', and adds the -following variables: - - `purescript-keyword-face' for reserved keywords and syntax, - `purescript-constructor-face' for data- and type-constructors, class names, - and module names, - `purescript-operator-face' for symbolic and alphanumeric operators, - `purescript-default-face' for ordinary code. - -The variables are initialised to the following font lock default faces: - - `purescript-keyword-face' `font-lock-keyword-face' - `purescript-constructor-face' `font-lock-type-face' - `purescript-operator-face' `font-lock-function-name-face' - `purescript-default-face' - -Two levels of fontification are defined: level one (the default) -and level two (more colour). The former does not colour operators. -Use the variable `font-lock-maximum-decoration' to choose -non-default levels of fontification. For example, adding this to -.emacs: - - (setq font-lock-maximum-decoration \\='((purescript-mode . 2) (t . 0))) - -uses level two fontification for `purescript-mode' and default level for -all other modes. See documentation on this variable for further -details. - -To alter an attribute of a face, add a hook. For example, to change -the foreground colour of comments to brown, add the following line to -.emacs: - - (add-hook \\='purescript-font-lock-hook - (lambda () - (set-face-foreground \\='purescript-comment-face \"brown\"))) - -Note that the colours available vary from system to system. To see -what colours are available on your system, call -`list-colors-display' from emacs. - -To turn font locking on for all PureScript buffers, add this to .emacs: - - (add-hook \\='purescript-mode-hook \\='turn-on-purescript-font-lock) - -To turn font locking on for the current buffer, call -`turn-on-purescript-font-lock'. To turn font locking off in the current -buffer, call `turn-off-purescript-font-lock'. - -Bird-style literate PureScript scripts are supported: If the value of -`purescript-literate-bird-style' (automatically set by the PureScript mode -of Moss&Thorn) is non-nil, a Bird-style literate script is assumed. - -Invokes `purescript-font-lock-hook' if not nil." - (purescript-font-lock-defaults-create) - (run-hooks 'purescript-font-lock-hook) - (turn-on-font-lock)) - -(defun turn-off-purescript-font-lock () - "Turns off font locking in current buffer." - (font-lock-mode -1)) - -;; Provide ourselves: - (provide 'purescript-font-lock) ;; Local Variables: From 866e81e1275948b353278e5bb11ed65e9c71b027 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 25 Feb 2025 21:01:51 +0300 Subject: [PATCH 52/99] Take into account a doc-comment may lack space before bar Credits for finding solution to Anders Lindgren at https://github.com/Lindydancer/font-lock-studio/issues/10 Fixes: https://github.com/purescript-emacs/purescript-mode/issues/16 --- purescript-font-lock.el | 4 ++-- tests/purescript-font-lock-tests.el | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 692ae46..7f1bb59 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -326,7 +326,7 @@ that should be commented under LaTeX-style literate scripts." ("\\s_\\{3,\\}" (0 (cond ((numberp (nth 4 (syntax-ppss))) ;; There are no such instances inside nestable comments nil) - ((string-match "\\`-*\\'" (match-string 0)) + ((string-match "\\`-*|?\\'" (match-string 0)) ;; Sequence of hyphens. Do nothing in ;; case of things like `{---'. nil) @@ -376,7 +376,7 @@ that should be commented under LaTeX-style literate scripts." ((and purescript-font-lock-docstrings (save-excursion (goto-char (nth 8 state)) - (looking-at "\\(-- \\|{-\\)[ \\t]*[|^]"))) + (looking-at "\\(--\\|{-\\)[ \\t]*[|^]"))) 'font-lock-doc-face) (t 'font-lock-comment-face))) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 984d33a..a661f6a 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -101,10 +101,11 @@ this = \"still a string\" (ert-deftest docs-bar-comment-different-spacings () (purescript-test-ranges - "-- | Docs comment 1 space + "--| Docs comment 0 space +-- | Docs comment 1 space -- | Docs comment many spaces " - '((1 57 font-lock-doc-face)))) + '((1 85 font-lock-doc-face)))) (ert-deftest docs-bar-comment-continuation () "Acc. to From 473cfbe9ffc745d61c214220d9073f49b7dc8ace Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 26 Feb 2025 00:10:48 +0300 Subject: [PATCH 53/99] Add missing `require 'autoloads` for `make all` to start working Worth noting that it uses deprecated autoloads lib, but offhand I couldn't figure out how to replace it with `loaddefs-generate-batch`, and I don't think it's even worth putting time into because nobody's likely gonna use this anyway. Let's just fix the make rule because it's easy to. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 354cc21..03a7e1e 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,7 @@ $(AUTOLOADS): $(ELFILES) purescript-mode.elc $(BATCH) \ --eval '(setq make-backup-files nil)' \ --eval '(setq generated-autoload-file "$(CURDIR)/$@")' \ + --eval "(require 'autoload)" \ -f batch-update-autoloads "." # HACK: embed version number into .elc file From c65f9aba241987518a30a9cdabec4c88a68bf668 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 27 Feb 2025 23:37:53 +0300 Subject: [PATCH 54/99] Add test with `instance` and other misc highlight --- tests/purescript-font-lock-tests.el | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index a661f6a..fe10e31 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -249,3 +249,57 @@ mkMyComponent = do (186 192 nil) (193 194 font-lock-type-face) (195 195 nil)))) + +(ert-deftest instance-miscellaneous () + "A diverse code snippet using `instance' (from Data.List module)" + (purescript-test-ranges + "instance extendNonEmptyList :: Extend NonEmptyList where + extend f w@(NonEmptyList (_ :| as)) = + NonEmptyList (f w :| (foldr go { val: Nil, acc: Nil } as).val) + where + go a { val, acc } = { val: f (NonEmptyList (a :| acc)) : val, acc: a : acc } +instance semigroupNonEmptyList :: Semigroup (NonEmptyList a) where + append (NonEmptyList (a :| as)) as' = + NonEmptyList (a :| as <> toList as') +derive newtype instance foldableNonEmptyList :: Foldable NonEmptyList +" + '((1 8 font-lock-keyword-face) (9 28 nil) + (29 30 font-lock-variable-name-face) (31 31 nil) + (32 37 font-lock-type-face) (38 38 nil) + (39 50 font-lock-type-face) (51 51 nil) + (52 56 font-lock-keyword-face) (57 69 nil) + (70 70 font-lock-variable-name-face) (71 71 nil) + (72 83 font-lock-type-face) (84 85 nil) + (86 86 font-lock-keyword-face) (87 87 nil) + (88 89 font-lock-type-face) (90 95 nil) + (96 96 font-lock-variable-name-face) (97 101 nil) + (102 113 font-lock-type-face) (114 119 nil) + (120 121 font-lock-type-face) (122 137 nil) + (138 138 font-lock-type-face) (139 139 nil) + (140 142 font-lock-type-face) (143 147 nil) + (148 148 font-lock-type-face) (149 149 nil) + (150 152 font-lock-type-face) (153 158 nil) + (159 159 font-lock-variable-name-face) (160 168 nil) + (169 173 font-lock-keyword-face) (174 196 nil) + (197 197 font-lock-variable-name-face) (198 203 nil) + (204 204 font-lock-type-face) (205 208 nil) + (209 220 font-lock-type-face) (221 224 nil) + (225 226 font-lock-type-face) (227 233 nil) + (234 234 font-lock-type-face) (235 243 nil) + (244 244 font-lock-type-face) (245 247 nil) + (248 248 font-lock-type-face) (249 255 nil) + (256 263 font-lock-keyword-face) (264 286 nil) + (287 288 font-lock-variable-name-face) (289 289 nil) + (290 298 font-lock-type-face) (299 300 nil) + (301 312 font-lock-type-face) (313 316 nil) + (317 321 font-lock-keyword-face) (322 332 nil) + (333 344 font-lock-type-face) (345 348 nil) + (349 350 font-lock-type-face) (351 360 nil) + (361 361 font-lock-variable-name-face) (362 366 nil) + (367 378 font-lock-type-face) (379 382 nil) + (383 384 font-lock-type-face) (385 388 nil) + (389 390 font-lock-variable-name-face) (391 403 nil) + (404 409 font-lock-keyword-face) (410 448 nil) + (449 450 font-lock-variable-name-face) (451 451 nil) + (452 459 font-lock-type-face) (460 460 nil) + (461 472 font-lock-type-face) (473 473 nil)))) From d28df6908f70f95d72f8364955ce5bd1b5a2db7b Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 5 Mar 2025 19:09:02 +0300 Subject: [PATCH 55/99] Remove `sexp-show` handling code It turns out this file wasn't in the build system and was causing a lot of warnings upon compilation. Further digging into what is that it does revealed it is a code for handling `sexp-show` from Hackage to do some Show-related edits in the buffer. However, it ain't clear how it's supposed to work (sexp-show just hangs when invoked with --help) and if it's even useful for PureScript (the file was part of the haskell-mode codebase when the project was forked). Original haskell-mode removed this code in 2015 here https://github.com/haskell/haskell-mode/pull/616 with commentary: > It requires the sexp-show package (which hasn't been updated since 2012 > and was abandoned in 2014) to be installed from Hackage to work. > However, even if it's customization option is enabled it doesn't > actually seem to be used/called anywhere, making it less than useful. > > Closes #615 Let's follow the trend. --- purescript-show.el | 259 --------------------------------------------- 1 file changed, 259 deletions(-) delete mode 100644 purescript-show.el diff --git a/purescript-show.el b/purescript-show.el deleted file mode 100644 index f380329..0000000 --- a/purescript-show.el +++ /dev/null @@ -1,259 +0,0 @@ -;;; purescript-show.el --- A pretty printer for PureScript Show values -*- lexical-binding: t -*- - -;; Copyright (C) 2011 Chris Done - -;; Author: Chris Done - -;; This file is not part of GNU Emacs. - -;; 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 -;; . - -;;; Commentary: - -;; It doesn't support some number literals (probably). I'm not -;; precisely sure what values Show will always produce. There is -;; however a test suite available, so patches for extra Show support -;; is welcome and should be easy to test. - -;;; Code: - -(defvar sexp-show "sexp-show") -(require 'purescript-string) -(require 'cl-lib) - -(defun purescript-show-replace-region () - "Replace the given region with a pretty printed version." - (interactive) - (purescript-show-replace (region-beginning) (region-end))) - -;;;###autoload -(defun purescript-show-replace (start end) - "Replace the given region containing a Show value with a pretty - printed collapsible version." - (let ((text (buffer-substring-no-properties start end))) - (goto-char start) - (delete-region start end) - (purescript-show-parse-and-insert text))) - -;;;###autoload -(defun purescript-show-parse-and-insert (given) - "Parse a `string' containing a Show instance value and insert - it pretty printed into the current buffer." - (when (not (string= "" (purescript-trim given))) - (let ((current-column (- (point) - (line-beginning-position))) - (result (purescript-show-parse given))) - (if (string-match "^[\\(]" result) - (let ((v (read result))) - (if (equal (car v) 'arbitrary) - (insert given) - (purescript-show-insert-pretty current-column v))) - (insert given))))) - -;;;###autoload -(defun purescript-show-parse (given) - "Parse the given input into a tree." - (with-temp-buffer - (insert given) - (shell-command-on-region - (point-min) - (point-max) - sexp-show - t) - (buffer-substring-no-properties (point-min) (point-max)))) - -(defun purescript-show-insert-pretty (column tree &optional parens) - "Insert a Show `tree' into the current buffer with collapsible nodes." - (cl-case (car tree) - ('list (let ((start (point))) - (insert "[") - (purescript-show-mapcar/i (lambda (x i len) - (purescript-show-insert-pretty (+ column 1) x) - (unless (> i (- len 2)) - (if (< (+ column (length (purescript-show-pretty tree parens))) - 80) - (insert ",") - (insert (concat ",\n" (purescript-show-indent (+ 1 column) "")))))) - (cdr tree)) - (insert "]"))) - ('tuple (let ((start (point))) - (insert "(") - (purescript-show-mapcar/i (lambda (x i len) - (purescript-show-insert-pretty (+ column 1) x) - (unless (> i (- len 2)) - (if (< (+ column (length (purescript-show-pretty tree parens))) - 80) - (insert ",") - (insert (concat ",\n" (purescript-show-indent (+ 1 column) "")))))) - (cdr tree)) - (insert ")"))) - ('record - (let ((record (cdr tree)) (overlay (list 'nil))) - (insert (if parens "(" "")) - (let ((link-start (point))) - (insert (car record)) - (let ((button (make-text-button link-start (point) :type 'purescript-show-toggle-button))) - (put-text-property link-start (point) 'face 'font-lock-type-face) - (button-put button 'overlay overlay))) - (insert " {\n") - (let ((curly-start (1- (point))) - (show-len (+ column (length (purescript-show-pretty tree parens))))) - (purescript-show-mapcar/i (lambda (field i len) - (insert - (purescript-show-indent - (if (and (> i 0) (< show-len 80)) 0 column) - (car field))) - (insert " = ") - (put-text-property (- (point) 3) (point) 'face - 'font-lock-constant-face) - (purescript-show-insert-pretty - (if (< show-len 80) - 0 - (+ (length (car field)) column 3)) - (cdr field)) - (unless (> i (- len 2)) - (if (< show-len 80) - (insert ", ") - (insert ",\n")))) - (cdr record)) - (insert (concat "\n" (purescript-show-indent column "}"))) - (progn - (setf (car overlay) (make-overlay curly-start (- (point) 1) nil t)) - (overlay-put (car overlay) 'invisible t)) - (insert (if parens ")" ""))))) - ('num (let ((num-start (point))) - (insert (format "%d" (cdr tree))) - (put-text-property num-start (point) 'face 'font-lock-constant-face))) - ('string (let ((str-start (point))) - (insert "\"") - (if (< (+ column (length (cdr tree))) 60) - (progn - (insert (format "%s" (cdr tree))) - (put-text-property (+ 1 str-start) (point) 'face 'font-lock-string-face)) - (progn - (insert "…") - (insert (format "%s" (cdr tree))) - (let ((overlay (make-overlay (+ 2 str-start) (point) nil t))) - (overlay-put overlay 'invisible t) - (put-text-property (+ 2 str-start) (point) 'face 'font-lock-string-face) - (let ((button (make-text-button (+ 1 str-start) (+ 2 str-start) - :type 'purescript-show-toggle-button))) - (put-text-property (+ 1 str-start) (+ 2 str-start) - 'face 'font-lock-keyword-face) - (button-put button 'overlay (list overlay)) - (button-put button 'hide-on-click t))))) - (insert "\""))) - ('data (let ((data (cdr tree))) - (insert (if parens "(" "")) - (let ((cons-start (point))) - (insert (car data)) - (put-text-property cons-start (point) 'face 'font-lock-type-face)) - (unless (null (cdr data)) - (progn (insert " ") - (purescript-show-mapcar/i - (lambda (x i len) - (purescript-show-insert-pretty column x t) - (unless (> i (- len 2)) - (insert " "))) - (cdr data)))) - (insert (if parens ")" "")))) - ('char (progn (insert "'") - (insert (char-to-string (cdr tree))) - (put-text-property (- (point) 1) (point) 'face 'font-lock-string-face) - (insert "'"))) - ('arbitrary (let ((start (point))) - (insert (cdr tree)) - (put-text-property start (point) 'face 'font-lock-comment-face))) - (otherwise (error "Unsupported node type: %S" tree)))) - -(define-button-type 'purescript-show-toggle-button - 'action 'purescript-show-toggle-button-callback - 'follow-link t - 'help-echo "Click to expand…") - -(defun purescript-show-toggle-button-callback (btn) - "The callback to toggle the overlay visibility." - (let ((overlay (button-get btn 'overlay))) - (when overlay - (overlay-put (car overlay) - 'invisible (not (overlay-get (car overlay) - 'invisible))))) - (let ((hide (button-get btn 'remove-on-click))) - (when hide - (button-put btn 'invisible t)))) - -(defun purescript-show-pretty (tree &optional parens) - "Show a Show `tree'." - (cl-case (car tree) - ('list (format "[%s]" - (mapconcat - (lambda (x) - (purescript-show-pretty x)) - (cdr tree) - ","))) - ('record (let ((record (cdr tree))) - (format "%s%s {%s}%s" - (if parens "(" "") - (car record) - (mapconcat (lambda (field) - (format "%s = %s" - (car field) - (purescript-show-pretty (cdr field)))) - (cdr record) - ", ") - (if parens ")" "")))) - ('num (format "%s" (cdr tree))) - ('string (format "%S" (cdr tree))) - ('data (let ((data (cdr tree))) - (format "%s%s%s%s" - (if parens "(" "") - (car data) - (if (null (cdr data)) - "" - (concat " " - (mapconcat - (lambda (x) (purescript-show-pretty x t)) - (cdr data) - " "))) - (if parens ")" "")))) - ('tuple (format "(%s)" - (mapconcat - (lambda (x) - (purescript-show-pretty x)) - (cdr tree) - ","))) - ('char (format "'%s'" (if (= (cdr tree) ?') - "\\'" - (char-to-string (cdr tree))))) - ('arbitrary (cdr tree)) - (otherwise (error "Unsupported node type: %S" tree)))) - -(defun purescript-show-mapcar/i (f xs) - "Map `f' across `xs' giving the index and length to `f' as extra parameters." - (let ((len (length xs)) - (i 0)) - (mapcar (lambda (x) - (funcall f x i len) - (setq i (1+ i))) - xs))) - -(defun purescript-show-indent (n s) - "Indent a string `s' at colum `n'." - (concat (make-string n ? ) - s)) - -(provide 'purescript-show) - -;;; purescript-show.el ends here From 8886f6672f56846cedbebd0da9c3498e87a904d5 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Wed, 5 Mar 2025 19:20:07 +0300 Subject: [PATCH 56/99] Fix "unused arg" warning in `purescript-presentation-mode` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm not sure if the mode is even useful in Purescript because I'm not exactly clear what it does (keep in mind this code was part of haskell-mode before fork happened), but let's for now at least make sure it doesn't produce warning and is included in compilation. Fixes warning: purescript-presentation-mode.el:38:33: Error: Unused lexical argument ‘session’ --- Makefile | 1 + purescript-presentation-mode.el | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 03a7e1e..3740ef0 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ ELFILES = \ purescript-mode.el \ purescript-move-nested.el \ purescript-navigate-imports.el \ + purescript-presentation-mode.el \ purescript-simple-indent.el \ purescript-sort-imports.el \ purescript-str.el \ diff --git a/purescript-presentation-mode.el b/purescript-presentation-mode.el index 1a8fa9b..8dcd86c 100644 --- a/purescript-presentation-mode.el +++ b/purescript-presentation-mode.el @@ -35,7 +35,7 @@ (define-key purescript-presentation-mode-map (kbd "q") 'quit-window) -(defun purescript-present (name session code) +(defun purescript-present (name _ code) "Present CODE in a popup buffer suffixed with NAME and set SESSION as the current purescript-session." (let* ((name (format "*PureScript Presentation%s*" name)) From 5532b19ae6c20bea82d1eb1c45c8632695655c79 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 7 Apr 2025 19:18:58 +0300 Subject: [PATCH 57/99] font-lock: highlight "foreign import" if no further text Prior to this commit a valid code like foreign import foo wasn't getting correctly highlighted. This fixes it. While doing so, we also remove all the ccall/stdcall/etc stuff, which is a legacy from haskell-mode and doesn't exist in purescript. --- purescript-font-lock.el | 9 ++---- tests/purescript-font-lock-tests.el | 46 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 7f1bb59..595219b 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -223,13 +223,10 @@ Returns keywords suitable for `font-lock-keywords'." (4 (symbol-value 'purescript-keyword-face) nil lax)) (,reservedsym 1 (symbol-value 'purescript-operator-face)) - ;; Special case for `foreign import' - ;; keywords in foreign import statements but are not otherwise reserved. - ("\\<\\(foreign\\)[ \t]+\\(import\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?\\(?:\\(safe\\|unsafe\\|interruptible\\)[ \t]+\\)?" + ;; Case for `foreign import' + ("\\<\\(foreign\\)[ \t]+\\(import\\>\\)" (1 (symbol-value 'purescript-keyword-face) nil lax) - (2 (symbol-value 'purescript-keyword-face) nil lax) - (3 (symbol-value 'purescript-keyword-face) nil lax) - (4 (symbol-value 'purescript-keyword-face) nil lax)) + (2 (symbol-value 'purescript-keyword-face) nil lax)) (,reservedsym 1 (symbol-value 'purescript-operator-face)) ;; Special case for `foreign export' diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index fe10e31..4350b99 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -303,3 +303,49 @@ derive newtype instance foldableNonEmptyList :: Foldable NonEmptyList (449 450 font-lock-variable-name-face) (451 451 nil) (452 459 font-lock-type-face) (460 460 nil) (461 472 font-lock-type-face) (473 473 nil)))) + +(ert-deftest foreign-imports () + (purescript-test-ranges + "foreign import func2 :: Effect Int +foreign import func3 + :: Effect Int +foreign import + func4 :: Effect Int + foreign import func5 -- invalid indentation, but allowed in other context +" + '((1 7 font-lock-keyword-face) + (8 8 nil) + (9 14 font-lock-keyword-face) + (15 21 nil) + (22 23 font-lock-variable-name-face) + (24 24 nil) + (25 30 font-lock-type-face) + (31 31 nil) + (32 34 font-lock-type-face) + (35 35 nil) + (36 42 font-lock-keyword-face) + (43 43 nil) + (44 49 font-lock-keyword-face) + (50 58 nil) + (59 60 font-lock-variable-name-face) + (61 61 nil) + (62 67 font-lock-type-face) + (68 68 nil) + (69 71 font-lock-type-face) + (72 72 nil) + (73 79 font-lock-keyword-face) + (80 80 nil) + (81 86 font-lock-keyword-face) + (87 95 nil) + (96 97 font-lock-variable-name-face) + (98 98 nil) + (99 104 font-lock-type-face) + (105 105 nil) + (106 108 font-lock-type-face) + (109 111 nil) + (112 118 font-lock-keyword-face) + (119 119 nil) + (120 125 font-lock-keyword-face) + (126 132 nil) + (133 135 font-lock-comment-delimiter-face) + (136 185 font-lock-comment-face)))) From 165ed400f2abbdfab36bff0aa71fbdb4f261950b Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 7 Apr 2025 19:41:55 +0300 Subject: [PATCH 58/99] font-lock: "foreign import" can't be preceded by text on the line --- purescript-font-lock.el | 3 ++- tests/purescript-font-lock-tests.el | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 595219b..2dbb652 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -224,7 +224,8 @@ Returns keywords suitable for `font-lock-keywords'." (,reservedsym 1 (symbol-value 'purescript-operator-face)) ;; Case for `foreign import' - ("\\<\\(foreign\\)[ \t]+\\(import\\>\\)" + (,(rx line-start (0+ whitespace) + (group "foreign") (1+ whitespace) (group "import") word-end) (1 (symbol-value 'purescript-keyword-face) nil lax) (2 (symbol-value 'purescript-keyword-face) nil lax)) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 4350b99..269b839 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -312,6 +312,8 @@ foreign import func3 foreign import func4 :: Effect Int foreign import func5 -- invalid indentation, but allowed in other context +invalid_dont_highlight foreign import func6 +foreign importinvalid " '((1 7 font-lock-keyword-face) (8 8 nil) @@ -348,4 +350,8 @@ foreign import (120 125 font-lock-keyword-face) (126 132 nil) (133 135 font-lock-comment-delimiter-face) - (136 185 font-lock-comment-face)))) + (136 185 font-lock-comment-face) + (186 207 font-lock-function-name-face) + (208 229 nil) + (230 236 font-lock-function-name-face) + (237 251 nil)))) From 98648c3881757404b9768a0812a90c36969f20fc Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 7 Apr 2025 19:51:06 +0300 Subject: [PATCH 59/99] font-lock: remove "foreign export" highlight "foreign export" isn't a thing in PureScript. It's a legacy from haskell-mode, remove it. --- purescript-font-lock.el | 7 ------- 1 file changed, 7 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 2dbb652..2f6b01b 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -230,13 +230,6 @@ Returns keywords suitable for `font-lock-keywords'." (2 (symbol-value 'purescript-keyword-face) nil lax)) (,reservedsym 1 (symbol-value 'purescript-operator-face)) - ;; Special case for `foreign export' - ;; keywords in foreign export statements but are not otherwise reserved. - ("\\<\\(foreign\\)[ \t]+\\(export\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?" - (1 (symbol-value 'purescript-keyword-face) nil lax) - (2 (symbol-value 'purescript-keyword-face) nil lax) - (3 (symbol-value 'purescript-keyword-face) nil lax)) - ;; Toplevel Declarations. ;; Place them *before* generic id-and-op highlighting. (,topdecl-var (1 (symbol-value 'purescript-definition-face))) From 231c06f3f76e9c14a8f85a2792eb4580e4270f0f Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Fri, 2 May 2025 14:07:15 +0700 Subject: [PATCH 60/99] font-lock: unduplicate operator-faces and add tests --- purescript-font-lock.el | 2 - tests/purescript-font-lock-tests.el | 153 ++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 2 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 2f6b01b..aec52a9 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -222,14 +222,12 @@ Returns keywords suitable for `font-lock-keywords'." (3 (symbol-value 'purescript-keyword-face) nil lax) (4 (symbol-value 'purescript-keyword-face) nil lax)) - (,reservedsym 1 (symbol-value 'purescript-operator-face)) ;; Case for `foreign import' (,(rx line-start (0+ whitespace) (group "foreign") (1+ whitespace) (group "import") word-end) (1 (symbol-value 'purescript-keyword-face) nil lax) (2 (symbol-value 'purescript-keyword-face) nil lax)) - (,reservedsym 1 (symbol-value 'purescript-operator-face)) ;; Toplevel Declarations. ;; Place them *before* generic id-and-op highlighting. (,topdecl-var (1 (symbol-value 'purescript-definition-face))) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 269b839..1fd994d 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -355,3 +355,156 @@ foreign importinvalid (208 229 nil) (230 236 font-lock-function-name-face) (237 251 nil)))) + +(ert-deftest operator-faces-simple () + "Tests operator faces unrelated to backticks" + (purescript-test-ranges + "-- .. +import Data.Maybe (Maybe(..)) + +-- -> and :: +id :: a -> a +id = \\x -> x + +-- <- +main = do + n <- pure 42 + pure n + +-- => and = +showVal :: Show a => a -> String +showVal = show + +-- @ +firstElem j@(Just _) = j + +-- guard | +abs' x | x < 0 = -x + | otherwise = x + +-- ~ and unicode ∷ +toUnfoldable ∷ forall f. Unfoldable f => List ~> f +toUnfoldable = undefined + +-- : as an operator +arr :: Array Int +arr = 1 : [2,3] +" + '((1 3 font-lock-comment-delimiter-face) + (4 6 font-lock-comment-face) + (7 12 font-lock-keyword-face) + (13 13 nil) + (14 23 font-lock-type-face) + (24 25 nil) + (26 30 font-lock-type-face) + (31 31 nil) + (32 33 font-lock-variable-name-face) + (34 37 nil) + (38 40 font-lock-comment-delimiter-face) + (41 50 font-lock-comment-face) + (51 52 font-lock-function-name-face) + (53 53 nil) + (54 55 font-lock-variable-name-face) + (56 58 nil) + (59 60 font-lock-variable-name-face) + (61 63 nil) + (64 65 font-lock-function-name-face) + (66 66 nil) + (67 67 font-lock-variable-name-face) + (68 68 nil) + (69 69 font-lock-variable-name-face) + (70 71 nil) + (72 73 font-lock-variable-name-face) + (74 77 nil) + (78 80 font-lock-comment-delimiter-face) + (81 83 font-lock-comment-face) + (84 87 font-lock-function-name-face) + (88 88 nil) + (89 89 font-lock-variable-name-face) + (90 90 nil) + (91 92 font-lock-keyword-face) + (93 97 nil) + (98 99 font-lock-variable-name-face) + (100 118 nil) + (119 121 font-lock-comment-delimiter-face) + (122 130 font-lock-comment-face) + (131 137 font-lock-function-name-face) + (138 138 nil) + (139 140 font-lock-variable-name-face) + (141 141 nil) + (142 145 font-lock-type-face) + (146 148 nil) + (149 150 font-lock-variable-name-face) + (151 153 nil) + (154 155 font-lock-variable-name-face) + (156 156 nil) + (157 162 font-lock-type-face) + (163 163 nil) + (164 170 font-lock-function-name-face) + (171 171 nil) + (172 172 font-lock-variable-name-face) + (173 179 nil) + (180 182 font-lock-comment-delimiter-face) + (183 184 font-lock-comment-face) + (185 193 font-lock-function-name-face) + (194 195 nil) + (196 196 font-lock-variable-name-face) + (197 197 nil) + (198 201 font-lock-type-face) + (202 202 nil) + (203 203 font-lock-keyword-face) + (204 205 nil) + (206 206 font-lock-variable-name-face) + (207 210 nil) + (211 213 font-lock-comment-delimiter-face) + (214 221 font-lock-comment-face) + (222 225 font-lock-function-name-face) + (226 228 nil) + (229 229 font-lock-variable-name-face) + (230 232 nil) + (233 233 font-lock-variable-name-face) + (234 236 nil) + (237 237 font-lock-variable-name-face) + (238 238 nil) + (239 239 font-lock-variable-name-face) + (240 248 nil) + (249 249 font-lock-variable-name-face) + (250 260 nil) + (261 261 font-lock-variable-name-face) + (262 265 nil) + (266 268 font-lock-comment-delimiter-face) + (269 284 font-lock-comment-face) + (285 296 font-lock-function-name-face) + (297 297 nil) + (298 298 font-lock-variable-name-face) + (299 307 nil) + (308 308 font-lock-variable-name-face) + (309 309 nil) + (310 319 font-lock-type-face) + (320 322 nil) + (323 324 font-lock-variable-name-face) + (325 325 nil) + (326 329 font-lock-type-face) + (330 330 nil) + (331 332 font-lock-variable-name-face) + (333 335 nil) + (336 347 font-lock-function-name-face) + (348 348 nil) + (349 349 font-lock-variable-name-face) + (350 361 nil) + (362 364 font-lock-comment-delimiter-face) + (365 381 font-lock-comment-face) + (382 384 font-lock-function-name-face) + (385 385 nil) + (386 387 font-lock-variable-name-face) + (388 388 nil) + (389 393 font-lock-type-face) + (394 394 nil) + (395 397 font-lock-type-face) + (398 398 nil) + (399 401 font-lock-function-name-face) + (402 402 nil) + (403 403 font-lock-variable-name-face) + (404 406 nil) + (407 407 font-lock-type-face) + (408 414 nil)))) From d150f6d0692773b7c01657850c306c44d11ab90d Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 4 May 2025 15:30:36 +0700 Subject: [PATCH 61/99] font-lock: remove unused variable `keywords` It was used in the past for the purposes of some conditional at the end of the function, but the conditional was removed, so now `keywords` does nothing useful. So remove it as well. --- purescript-font-lock.el | 88 ++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index aec52a9..53fd8c9 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -204,52 +204,48 @@ Returns keywords suitable for `font-lock-keywords'." (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*`\\(" varid "\\)`")) (topdecl-sym (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*\\(" sym "\\)")) - (topdecl-sym2 (concat line-prefix "(\\(" sym "\\))")) - - keywords) - - (setq keywords - `(;; NOTICE the ordering below is significant - ;; - (,toplevel-keywords 1 (symbol-value 'purescript-keyword-face)) - (,reservedid 1 (symbol-value 'purescript-keyword-face)) - (,reservedsym 1 (symbol-value 'purescript-operator-face)) - ;; Special case for `as', `hiding', `safe' and `qualified', which are - ;; keywords in import statements but are not otherwise reserved. - ("\\\\)[ \t]*\\)?\\(?:\\(qualified\\>\\)[ \t]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\\\)?" - (1 (symbol-value 'purescript-keyword-face) nil lax) - (2 (symbol-value 'purescript-keyword-face) nil lax) - (3 (symbol-value 'purescript-keyword-face) nil lax) - (4 (symbol-value 'purescript-keyword-face) nil lax)) - - ;; Case for `foreign import' - (,(rx line-start (0+ whitespace) - (group "foreign") (1+ whitespace) (group "import") word-end) - (1 (symbol-value 'purescript-keyword-face) nil lax) - (2 (symbol-value 'purescript-keyword-face) nil lax)) - - ;; Toplevel Declarations. - ;; Place them *before* generic id-and-op highlighting. - (,topdecl-var (1 (symbol-value 'purescript-definition-face))) - (,topdecl-var2 (2 (symbol-value 'purescript-definition-face))) - (,topdecl-sym (2 (symbol-value 'purescript-definition-face))) - (,topdecl-sym2 (1 (symbol-value 'purescript-definition-face))) - - ;; These four are debatable... - ("(\\(,*\\|->\\))" 0 (symbol-value 'purescript-constructor-face)) - ("\\[\\]" 0 (symbol-value 'purescript-constructor-face)) - ;; Expensive. - (,qvarid 0 (symbol-value 'purescript-default-face)) - (,qconid 0 (symbol-value 'purescript-constructor-face)) - (,(concat "\`" varid "\`") 0 (symbol-value 'purescript-operator-face)) - ;; Expensive. - (,conid 0 (symbol-value 'purescript-constructor-face)) - - ;; Very expensive. - (,sym 0 (if (eq (char-after (match-beginning 0)) ?:) - purescript-constructor-face - purescript-operator-face)))) - keywords)) + (topdecl-sym2 (concat line-prefix "(\\(" sym "\\))"))) + + `(;; NOTICE the ordering below is significant + ;; + (,toplevel-keywords 1 (symbol-value 'purescript-keyword-face)) + (,reservedid 1 (symbol-value 'purescript-keyword-face)) + (,reservedsym 1 (symbol-value 'purescript-operator-face)) + ;; Special case for `as', `hiding', `safe' and `qualified', which are + ;; keywords in import statements but are not otherwise reserved. + ("\\\\)[ \t]*\\)?\\(?:\\(qualified\\>\\)[ \t]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\\\)?" + (1 (symbol-value 'purescript-keyword-face) nil lax) + (2 (symbol-value 'purescript-keyword-face) nil lax) + (3 (symbol-value 'purescript-keyword-face) nil lax) + (4 (symbol-value 'purescript-keyword-face) nil lax)) + + ;; Case for `foreign import' + (,(rx line-start (0+ whitespace) + (group "foreign") (1+ whitespace) (group "import") word-end) + (1 (symbol-value 'purescript-keyword-face) nil lax) + (2 (symbol-value 'purescript-keyword-face) nil lax)) + + ;; Toplevel Declarations. + ;; Place them *before* generic id-and-op highlighting. + (,topdecl-var (1 (symbol-value 'purescript-definition-face))) + (,topdecl-var2 (2 (symbol-value 'purescript-definition-face))) + (,topdecl-sym (2 (symbol-value 'purescript-definition-face))) + (,topdecl-sym2 (1 (symbol-value 'purescript-definition-face))) + + ;; These four are debatable... + ("(\\(,*\\|->\\))" 0 (symbol-value 'purescript-constructor-face)) + ("\\[\\]" 0 (symbol-value 'purescript-constructor-face)) + ;; Expensive. + (,qvarid 0 (symbol-value 'purescript-default-face)) + (,qconid 0 (symbol-value 'purescript-constructor-face)) + (,(concat "\`" varid "\`") 0 (symbol-value 'purescript-operator-face)) + ;; Expensive. + (,conid 0 (symbol-value 'purescript-constructor-face)) + + ;; Very expensive. + (,sym 0 (if (eq (char-after (match-beginning 0)) ?:) + purescript-constructor-face + purescript-operator-face))))) ;; The next three aren't used in Emacs 21. From 949f8273ffd87f0aeb0329e1db8e5d876c99dacb Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 4 May 2025 16:34:11 +0700 Subject: [PATCH 62/99] font-lock: highlight operators with "builtin" face What face is the most appropriate is arguable. Emacs 29.1 has "operator-face", but it's unavailable for older Emacs, and even for newer versions it's just "nil", so no highlight. Kinda pointless face. The current "variable-name" is definitely wrong though, because operators are far from being variables. And there's a separate "color-identifiers-mode" which uses this face to highlight similar variables, and that would work wrong for purescript-mode. Thus, replace the highlight to "builtin". --- purescript-font-lock.el | 2 +- tests/purescript-font-lock-tests.el | 116 ++++++++++++++-------------- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 53fd8c9..7816984 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -128,7 +128,7 @@ ;; This is probably just wrong, but it used to use ;; `font-lock-function-name-face' with a result that was not consistent with ;; other major modes, so I just exchanged with `purescript-definition-face'. -(defvar purescript-operator-face 'font-lock-variable-name-face) +(defvar purescript-operator-face 'font-lock-builtin-face) (defvar purescript-default-face nil) (defvar purescript-literate-comment-face 'font-lock-doc-face "Face with which to fontify literate comments. diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index 1fd994d..b9a1064 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -55,13 +55,13 @@ import Data.Either (Either(..)) (53 58 font-lock-keyword-face) (60 70 font-lock-type-face) (73 78 font-lock-type-face) - (80 81 font-lock-variable-name-face)))) + (80 81 font-lock-builtin-face)))) (ert-deftest string () (purescript-test-ranges "foo = \"hello\"" '((1 3 font-lock-function-name-face) - (5 5 font-lock-variable-name-face) + (5 5 font-lock-builtin-face) (7 13 font-lock-string-face)))) (ert-deftest multiline-string () @@ -71,7 +71,7 @@ hello \"\"\" " '((1 3 font-lock-function-name-face) - (5 5 font-lock-variable-name-face) + (5 5 font-lock-builtin-face) (7 19 font-lock-string-face)))) (ert-deftest multiline-string-with-hash () @@ -85,7 +85,7 @@ hello \"\"\" " '((1 3 font-lock-function-name-face) - (5 5 font-lock-variable-name-face) + (5 5 font-lock-builtin-face) (7 114 font-lock-string-face)))) (ert-deftest multiline-string-with-embedded-strings () @@ -96,7 +96,7 @@ this = \"still a string\" \"\"\" " '((1 3 font-lock-function-name-face) - (5 5 font-lock-variable-name-face) + (5 5 font-lock-builtin-face) (7 37 font-lock-string-face)))) (ert-deftest docs-bar-comment-different-spacings () @@ -163,11 +163,11 @@ noncomment (5 5 nil) (6 14 font-lock-type-face) (15 21 nil) - (22 22 font-lock-variable-name-face) + (22 22 font-lock-builtin-face) (23 23 nil) (24 29 font-lock-type-face) (30 37 nil) - (38 39 font-lock-variable-name-face) + (38 39 font-lock-builtin-face) (40 40 nil) (41 43 font-lock-type-face) (44 45 nil)))) @@ -205,47 +205,47 @@ mkMyComponent = do " '((1 13 font-lock-function-name-face) (14 14 nil) - (15 16 font-lock-variable-name-face) + (15 16 font-lock-builtin-face) (17 17 nil) (18 26 font-lock-type-face) (27 30 nil) (31 43 font-lock-function-name-face) (44 44 nil) - (45 45 font-lock-variable-name-face) + (45 45 font-lock-builtin-face) (46 46 nil) (47 48 font-lock-keyword-face) (49 61 nil) - (62 63 font-lock-variable-name-face) + (62 63 font-lock-builtin-face) (64 65 nil) (66 72 font-lock-type-face) (73 73 nil) - (74 75 font-lock-variable-name-face) + (74 75 font-lock-builtin-face) (76 76 nil) (77 79 font-lock-type-face) (80 81 nil) - (82 83 font-lock-variable-name-face) + (82 83 font-lock-builtin-face) (84 104 nil) (105 119 font-lock-string-face) (120 120 nil) - (121 121 font-lock-variable-name-face) + (121 121 font-lock-builtin-face) (122 122 font-lock-keyword-face) (123 123 nil) - (124 125 font-lock-variable-name-face) + (124 125 font-lock-builtin-face) (126 126 nil) (127 131 font-lock-type-face) - (132 132 font-lock-variable-name-face) + (132 132 font-lock-builtin-face) (133 134 font-lock-keyword-face) (135 149 nil) - (150 151 font-lock-variable-name-face) + (150 151 font-lock-builtin-face) (152 152 nil) (153 159 font-lock-type-face) (160 160 nil) - (161 162 font-lock-variable-name-face) + (161 162 font-lock-builtin-face) (163 181 nil) - (182 182 font-lock-variable-name-face) + (182 182 font-lock-builtin-face) (183 183 nil) (184 184 font-lock-type-face) - (185 185 font-lock-variable-name-face) + (185 185 font-lock-builtin-face) (186 192 nil) (193 194 font-lock-type-face) (195 195 nil)))) @@ -264,24 +264,24 @@ instance semigroupNonEmptyList :: Semigroup (NonEmptyList a) where derive newtype instance foldableNonEmptyList :: Foldable NonEmptyList " '((1 8 font-lock-keyword-face) (9 28 nil) - (29 30 font-lock-variable-name-face) (31 31 nil) + (29 30 font-lock-builtin-face) (31 31 nil) (32 37 font-lock-type-face) (38 38 nil) (39 50 font-lock-type-face) (51 51 nil) (52 56 font-lock-keyword-face) (57 69 nil) - (70 70 font-lock-variable-name-face) (71 71 nil) + (70 70 font-lock-builtin-face) (71 71 nil) (72 83 font-lock-type-face) (84 85 nil) (86 86 font-lock-keyword-face) (87 87 nil) (88 89 font-lock-type-face) (90 95 nil) - (96 96 font-lock-variable-name-face) (97 101 nil) + (96 96 font-lock-builtin-face) (97 101 nil) (102 113 font-lock-type-face) (114 119 nil) (120 121 font-lock-type-face) (122 137 nil) (138 138 font-lock-type-face) (139 139 nil) (140 142 font-lock-type-face) (143 147 nil) (148 148 font-lock-type-face) (149 149 nil) (150 152 font-lock-type-face) (153 158 nil) - (159 159 font-lock-variable-name-face) (160 168 nil) + (159 159 font-lock-builtin-face) (160 168 nil) (169 173 font-lock-keyword-face) (174 196 nil) - (197 197 font-lock-variable-name-face) (198 203 nil) + (197 197 font-lock-builtin-face) (198 203 nil) (204 204 font-lock-type-face) (205 208 nil) (209 220 font-lock-type-face) (221 224 nil) (225 226 font-lock-type-face) (227 233 nil) @@ -289,18 +289,18 @@ derive newtype instance foldableNonEmptyList :: Foldable NonEmptyList (244 244 font-lock-type-face) (245 247 nil) (248 248 font-lock-type-face) (249 255 nil) (256 263 font-lock-keyword-face) (264 286 nil) - (287 288 font-lock-variable-name-face) (289 289 nil) + (287 288 font-lock-builtin-face) (289 289 nil) (290 298 font-lock-type-face) (299 300 nil) (301 312 font-lock-type-face) (313 316 nil) (317 321 font-lock-keyword-face) (322 332 nil) (333 344 font-lock-type-face) (345 348 nil) (349 350 font-lock-type-face) (351 360 nil) - (361 361 font-lock-variable-name-face) (362 366 nil) + (361 361 font-lock-builtin-face) (362 366 nil) (367 378 font-lock-type-face) (379 382 nil) (383 384 font-lock-type-face) (385 388 nil) - (389 390 font-lock-variable-name-face) (391 403 nil) + (389 390 font-lock-builtin-face) (391 403 nil) (404 409 font-lock-keyword-face) (410 448 nil) - (449 450 font-lock-variable-name-face) (451 451 nil) + (449 450 font-lock-builtin-face) (451 451 nil) (452 459 font-lock-type-face) (460 460 nil) (461 472 font-lock-type-face) (473 473 nil)))) @@ -319,7 +319,7 @@ foreign importinvalid (8 8 nil) (9 14 font-lock-keyword-face) (15 21 nil) - (22 23 font-lock-variable-name-face) + (22 23 font-lock-builtin-face) (24 24 nil) (25 30 font-lock-type-face) (31 31 nil) @@ -329,7 +329,7 @@ foreign importinvalid (43 43 nil) (44 49 font-lock-keyword-face) (50 58 nil) - (59 60 font-lock-variable-name-face) + (59 60 font-lock-builtin-face) (61 61 nil) (62 67 font-lock-type-face) (68 68 nil) @@ -339,7 +339,7 @@ foreign importinvalid (80 80 nil) (81 86 font-lock-keyword-face) (87 95 nil) - (96 97 font-lock-variable-name-face) + (96 97 font-lock-builtin-face) (98 98 nil) (99 104 font-lock-type-face) (105 105 nil) @@ -398,105 +398,105 @@ arr = 1 : [2,3] (24 25 nil) (26 30 font-lock-type-face) (31 31 nil) - (32 33 font-lock-variable-name-face) + (32 33 font-lock-builtin-face) (34 37 nil) (38 40 font-lock-comment-delimiter-face) (41 50 font-lock-comment-face) (51 52 font-lock-function-name-face) (53 53 nil) - (54 55 font-lock-variable-name-face) + (54 55 font-lock-builtin-face) (56 58 nil) - (59 60 font-lock-variable-name-face) + (59 60 font-lock-builtin-face) (61 63 nil) (64 65 font-lock-function-name-face) (66 66 nil) - (67 67 font-lock-variable-name-face) + (67 67 font-lock-builtin-face) (68 68 nil) - (69 69 font-lock-variable-name-face) + (69 69 font-lock-builtin-face) (70 71 nil) - (72 73 font-lock-variable-name-face) + (72 73 font-lock-builtin-face) (74 77 nil) (78 80 font-lock-comment-delimiter-face) (81 83 font-lock-comment-face) (84 87 font-lock-function-name-face) (88 88 nil) - (89 89 font-lock-variable-name-face) + (89 89 font-lock-builtin-face) (90 90 nil) (91 92 font-lock-keyword-face) (93 97 nil) - (98 99 font-lock-variable-name-face) + (98 99 font-lock-builtin-face) (100 118 nil) (119 121 font-lock-comment-delimiter-face) (122 130 font-lock-comment-face) (131 137 font-lock-function-name-face) (138 138 nil) - (139 140 font-lock-variable-name-face) + (139 140 font-lock-builtin-face) (141 141 nil) (142 145 font-lock-type-face) (146 148 nil) - (149 150 font-lock-variable-name-face) + (149 150 font-lock-builtin-face) (151 153 nil) - (154 155 font-lock-variable-name-face) + (154 155 font-lock-builtin-face) (156 156 nil) (157 162 font-lock-type-face) (163 163 nil) (164 170 font-lock-function-name-face) (171 171 nil) - (172 172 font-lock-variable-name-face) + (172 172 font-lock-builtin-face) (173 179 nil) (180 182 font-lock-comment-delimiter-face) (183 184 font-lock-comment-face) (185 193 font-lock-function-name-face) (194 195 nil) - (196 196 font-lock-variable-name-face) + (196 196 font-lock-builtin-face) (197 197 nil) (198 201 font-lock-type-face) (202 202 nil) (203 203 font-lock-keyword-face) (204 205 nil) - (206 206 font-lock-variable-name-face) + (206 206 font-lock-builtin-face) (207 210 nil) (211 213 font-lock-comment-delimiter-face) (214 221 font-lock-comment-face) (222 225 font-lock-function-name-face) (226 228 nil) - (229 229 font-lock-variable-name-face) + (229 229 font-lock-builtin-face) (230 232 nil) - (233 233 font-lock-variable-name-face) + (233 233 font-lock-builtin-face) (234 236 nil) - (237 237 font-lock-variable-name-face) + (237 237 font-lock-builtin-face) (238 238 nil) - (239 239 font-lock-variable-name-face) + (239 239 font-lock-builtin-face) (240 248 nil) - (249 249 font-lock-variable-name-face) + (249 249 font-lock-builtin-face) (250 260 nil) - (261 261 font-lock-variable-name-face) + (261 261 font-lock-builtin-face) (262 265 nil) (266 268 font-lock-comment-delimiter-face) (269 284 font-lock-comment-face) (285 296 font-lock-function-name-face) (297 297 nil) - (298 298 font-lock-variable-name-face) + (298 298 font-lock-builtin-face) (299 307 nil) - (308 308 font-lock-variable-name-face) + (308 308 font-lock-builtin-face) (309 309 nil) (310 319 font-lock-type-face) (320 322 nil) - (323 324 font-lock-variable-name-face) + (323 324 font-lock-builtin-face) (325 325 nil) (326 329 font-lock-type-face) (330 330 nil) - (331 332 font-lock-variable-name-face) + (331 332 font-lock-builtin-face) (333 335 nil) (336 347 font-lock-function-name-face) (348 348 nil) - (349 349 font-lock-variable-name-face) + (349 349 font-lock-builtin-face) (350 361 nil) (362 364 font-lock-comment-delimiter-face) (365 381 font-lock-comment-face) (382 384 font-lock-function-name-face) (385 385 nil) - (386 387 font-lock-variable-name-face) + (386 387 font-lock-builtin-face) (388 388 nil) (389 393 font-lock-type-face) (394 394 nil) @@ -504,7 +504,7 @@ arr = 1 : [2,3] (398 398 nil) (399 401 font-lock-function-name-face) (402 402 nil) - (403 403 font-lock-variable-name-face) + (403 403 font-lock-builtin-face) (404 406 nil) (407 407 font-lock-type-face) (408 414 nil)))) From 49e0faeca49dad987998080a743266af69ab4f6b Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 4 May 2025 15:21:47 +0700 Subject: [PATCH 63/99] font-lock: cover more operators than just the builtins For example, the tuple construction `1 /\ 2` was weirdly half-haighlighted before this commit, because it wasn't covered by the "operators regexp" and was getting caught by some other rule. Fix that. For inspiration, I looked at the regexp from the official Atom purescript highlight https://github.com/purescript-contrib/atom-language-purescript/blob/d17eee55b12c140e8a1a750cce7e5aa9b09653c2/src/purescript.coffee#L32 that one works a bit differently, it excludes chars from class. AFAIK Emacs can't do that, so instead I just enlisted the symbols. One thing I did differently though is including colon, because it is a valid operator in PureScript (for List), I think Atom has a bug in their regexp. --- purescript-font-lock.el | 10 ++++---- tests/purescript-font-lock-tests.el | 36 +++++++++++++++++++---------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 7816984..8c76689 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -165,12 +165,10 @@ Returns keywords suitable for `font-lock-keywords'." ;; be thrown for some reason by backslash's escape syntax. "\\(\\s_\\|\\\\\\)+") - ;; Reserved operations - (reservedsym + (operator (concat "\\S_" - ;; (regexp-opt '(".." "::" "=" "\\" "|" "<-" "->" - ;; "@" "~" "=>") t) - "\\(->\\|\\.\\.\\|::\\|∷\\|<-\\|=>\\|[=@\\|~]\\)" + ;; All punctuation, excluding (),;[]{}_"'` + "\\([!@#$%^&*+\\-./<=>?@|~:∷\\\\]+\\)" "\\S_")) ;; These are only keywords when appear at top-level, optionally with ;; indentation. They are not reserved and in other levels would represent @@ -210,7 +208,7 @@ Returns keywords suitable for `font-lock-keywords'." ;; (,toplevel-keywords 1 (symbol-value 'purescript-keyword-face)) (,reservedid 1 (symbol-value 'purescript-keyword-face)) - (,reservedsym 1 (symbol-value 'purescript-operator-face)) + (,operator 1 (symbol-value 'purescript-operator-face)) ;; Special case for `as', `hiding', `safe' and `qualified', which are ;; keywords in import statements but are not otherwise reserved. ("\\\\)[ \t]*\\)?\\(?:\\(qualified\\>\\)[ \t]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\\\)?" diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index b9a1064..db20cdb 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -271,33 +271,33 @@ derive newtype instance foldableNonEmptyList :: Foldable NonEmptyList (70 70 font-lock-builtin-face) (71 71 nil) (72 83 font-lock-type-face) (84 85 nil) (86 86 font-lock-keyword-face) (87 87 nil) - (88 89 font-lock-type-face) (90 95 nil) + (88 89 font-lock-builtin-face) (90 95 nil) (96 96 font-lock-builtin-face) (97 101 nil) (102 113 font-lock-type-face) (114 119 nil) - (120 121 font-lock-type-face) (122 137 nil) - (138 138 font-lock-type-face) (139 139 nil) + (120 121 font-lock-builtin-face) (122 137 nil) + (138 138 font-lock-builtin-face) (139 139 nil) (140 142 font-lock-type-face) (143 147 nil) - (148 148 font-lock-type-face) (149 149 nil) + (148 148 font-lock-builtin-face) (149 149 nil) (150 152 font-lock-type-face) (153 158 nil) (159 159 font-lock-builtin-face) (160 168 nil) (169 173 font-lock-keyword-face) (174 196 nil) (197 197 font-lock-builtin-face) (198 203 nil) - (204 204 font-lock-type-face) (205 208 nil) + (204 204 font-lock-builtin-face) (205 208 nil) (209 220 font-lock-type-face) (221 224 nil) - (225 226 font-lock-type-face) (227 233 nil) - (234 234 font-lock-type-face) (235 243 nil) - (244 244 font-lock-type-face) (245 247 nil) - (248 248 font-lock-type-face) (249 255 nil) + (225 226 font-lock-builtin-face) (227 233 nil) + (234 234 font-lock-builtin-face) (235 243 nil) + (244 244 font-lock-builtin-face) (245 247 nil) + (248 248 font-lock-builtin-face) (249 255 nil) (256 263 font-lock-keyword-face) (264 286 nil) (287 288 font-lock-builtin-face) (289 289 nil) (290 298 font-lock-type-face) (299 300 nil) (301 312 font-lock-type-face) (313 316 nil) (317 321 font-lock-keyword-face) (322 332 nil) (333 344 font-lock-type-face) (345 348 nil) - (349 350 font-lock-type-face) (351 360 nil) + (349 350 font-lock-builtin-face) (351 360 nil) (361 361 font-lock-builtin-face) (362 366 nil) (367 378 font-lock-type-face) (379 382 nil) - (383 384 font-lock-type-face) (385 388 nil) + (383 384 font-lock-builtin-face) (385 388 nil) (389 390 font-lock-builtin-face) (391 403 nil) (404 409 font-lock-keyword-face) (410 448 nil) (449 450 font-lock-builtin-face) (451 451 nil) @@ -506,5 +506,17 @@ arr = 1 : [2,3] (402 402 nil) (403 403 font-lock-builtin-face) (404 406 nil) - (407 407 font-lock-type-face) + (407 407 font-lock-builtin-face) (408 414 nil)))) + +(ert-deftest tuple-and-cap-highlighted () + (purescript-test-ranges + "myTuple = 1 /\\ (2 ^ 3)" + '((1 7 font-lock-function-name-face) + (8 8 nil) + (9 9 font-lock-builtin-face) + (10 12 nil) + (13 14 font-lock-builtin-face) + (15 18 nil) + (19 19 font-lock-builtin-face) + (20 23 nil)))) From f52227bfb8de304f353fd124baef8c0563f7d3c0 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 5 May 2025 11:24:31 +0700 Subject: [PATCH 64/99] font-lock: remove useless rule for (,) and (->) The (,) and (->) don't have much use in PureScript, nor in Haskell for that matter. In Haskell (,) was a prefix notation for tuple construction, but in PureScript this operator isn't a thing. Both trigger "syntax error" in PureScript (and (->) doesn't work even in Haskell). Indeed a debatable rule. Let's just remove it. --- purescript-font-lock.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 8c76689..9d2606a 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -230,8 +230,7 @@ Returns keywords suitable for `font-lock-keywords'." (,topdecl-sym (2 (symbol-value 'purescript-definition-face))) (,topdecl-sym2 (1 (symbol-value 'purescript-definition-face))) - ;; These four are debatable... - ("(\\(,*\\|->\\))" 0 (symbol-value 'purescript-constructor-face)) + ;; This one is debatable… ("\\[\\]" 0 (symbol-value 'purescript-constructor-face)) ;; Expensive. (,qvarid 0 (symbol-value 'purescript-default-face)) From 1a0e9398e4b8a42a4fec7464dfe6fb1bc5346480 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 5 May 2025 22:16:24 +0700 Subject: [PATCH 65/99] font-lock: remove unused escaping from backtick-operator rule Backticks don't need to be escaped. --- purescript-font-lock.el | 2 +- tests/purescript-font-lock-tests.el | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 9d2606a..c024968 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -235,7 +235,7 @@ Returns keywords suitable for `font-lock-keywords'." ;; Expensive. (,qvarid 0 (symbol-value 'purescript-default-face)) (,qconid 0 (symbol-value 'purescript-constructor-face)) - (,(concat "\`" varid "\`") 0 (symbol-value 'purescript-operator-face)) + (,(concat "`" varid "`") 0 (symbol-value 'purescript-operator-face)) ;; Expensive. (,conid 0 (symbol-value 'purescript-constructor-face)) diff --git a/tests/purescript-font-lock-tests.el b/tests/purescript-font-lock-tests.el index db20cdb..b745c4c 100644 --- a/tests/purescript-font-lock-tests.el +++ b/tests/purescript-font-lock-tests.el @@ -520,3 +520,13 @@ arr = 1 : [2,3] (15 18 nil) (19 19 font-lock-builtin-face) (20 23 nil)))) + +(ert-deftest backtick-operator () + (purescript-test-ranges + "var = 1 `func` 2" + '((1 3 font-lock-function-name-face) + (4 4 nil) + (5 5 font-lock-builtin-face) + (6 8 nil) + (9 14 font-lock-builtin-face) + (15 17 nil)))) From a5fb6ec9aca7bdb8557939f221a836c5eaa46d43 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 5 May 2025 22:23:15 +0700 Subject: [PATCH 66/99] purescript-font-lock.el: remove mention of xemacs and GreenCard Greencard is Haskell specific thing for FFI. XEmacs has been unmaintainted for a long time, no point adding the support now. And the ship has long sailed for the comment about func/var prefixes. --- purescript-font-lock.el | 9 --------- 1 file changed, 9 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 53fd8c9..e50163e 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -52,15 +52,6 @@ ;; highlighted as constructors or not. Should the `->' in ;; `id :: a -> a' be considered a constructor or a keyword? If so, ;; how do we distinguish this from `\x -> x'? What about the `\'? -;; -;; . XEmacs can support both `--' comments and `{- -}' comments -;; simultaneously. If XEmacs is detected, this should be used. -;; -;; . Support for GreenCard? -;; -;; -;; All functions/variables start with -;; `(turn-(on/off)-)purescript-font-lock' or `purescript-fl-'. ;;; Change Log: From 23896abc304ff2c30b1f4fdbb5ed4ba797c29bf4 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 5 May 2025 22:27:00 +0700 Subject: [PATCH 67/99] purescript-font-lock.el: remove purescript-fl-latex-cache-in-comment It is unused and apparently was some legacy from Emacs 21 from long ago. --- purescript-font-lock.el | 49 ----------------------------------------- 1 file changed, 49 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index e50163e..55fc399 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -238,55 +238,6 @@ Returns keywords suitable for `font-lock-keywords'." purescript-constructor-face purescript-operator-face))))) -;; The next three aren't used in Emacs 21. - -(defvar purescript-fl-latex-cache-pos nil - "Position of cache point used by `purescript-fl-latex-cache-in-comment'. -Should be at the start of a line.") - -(defvar purescript-fl-latex-cache-in-comment nil - "If `purescript-fl-latex-cache-pos' is outside a -\\begin{code}..\\end{code} block (and therefore inside a comment), -this variable is set to t, otherwise nil.") - -(defun purescript-fl-latex-comments (end) - "Sets `match-data' according to the region of the buffer before end -that should be commented under LaTeX-style literate scripts." - (let ((start (point))) - (if (= start end) - ;; We're at the end. No more to fontify. - nil - (if (not (eq start purescript-fl-latex-cache-pos)) - ;; If the start position is not cached, calculate the state - ;; of the start. - (progn - (setq purescript-fl-latex-cache-pos start) - ;; If the previous \begin{code} or \end{code} is a - ;; \begin{code}, then start is not in a comment, otherwise - ;; it is in a comment. - (setq purescript-fl-latex-cache-in-comment - (if (and - (re-search-backward - "^\\(\\(\\\\begin{code}\\)\\|\\(\\\\end{code}\\)\\)$" - (point-min) t) - (match-end 2)) - nil t)) - ;; Restore position. - (goto-char start))) - (if purescript-fl-latex-cache-in-comment - (progn - ;; If start is inside a comment, search for next \begin{code}. - (re-search-forward "^\\\\begin{code}$" end 'move) - ;; Mark start to end of \begin{code} (if present, till end - ;; otherwise), as a comment. - (set-match-data (list start (point))) - ;; Return point, as a normal regexp would. - (point)) - ;; If start is inside a code block, search for next \end{code}. - (if (re-search-forward "^\\\\end{code}$" end t) - ;; If one found, mark it as a comment, otherwise finish. - (point)))))) - (defconst purescript-basic-syntactic-keywords '(;; Character constants (since apostrophe can't have string syntax). ;; Beware: do not match something like 's-}' or '\n"+' since the first ' From 64fa1f30236efb6456b1c1fa3ca0339c569bd14e Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 5 May 2025 22:30:00 +0700 Subject: [PATCH 68/99] purescript-font-lock.el: remove misleading comment about `undefined` `undefined` is used in PureSript, but exists in the form of a separate library. --- purescript-font-lock.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 55fc399..bf99bec 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -98,7 +98,7 @@ ("&&" . ,(decode-char 'ucs #X2227)) ("||" . ,(decode-char 'ucs #X2228)) ("sqrt" . ,(decode-char 'ucs #X221A)) - ("undefined" . ,(decode-char 'ucs #X22A5)) ;; Not really needed for Purescript + ("undefined" . ,(decode-char 'ucs #X22A5)) ("pi" . ,(decode-char 'ucs #X3C0)) ("~>" . ,(decode-char 'ucs 8669)) ;; Omega language ("-<" . ,(decode-char 'ucs 8610)) ;; Paterson's arrow syntax From 652c7cc97285292687e9545bdfdf30dc25f8efec Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 5 May 2025 22:36:21 +0700 Subject: [PATCH 69/99] purescript-font-lock.el: remove changelog from the file We have git now, the code mentioning things from a decade ago doesn't sound too useful. --- purescript-font-lock.el | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index bf99bec..463048a 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -53,29 +53,6 @@ ;; `id :: a -> a' be considered a constructor or a keyword? If so, ;; how do we distinguish this from `\x -> x'? What about the `\'? -;;; Change Log: - -;; Version 1.3: -;; From Dave Love: -;; Support for proper behaviour (including with Unicode identifiers) -;; in Emacs 21 only hacked in messily to avoid disturbing the old -;; stuff. Needs integrating more cleanly. Allow literate comment -;; face to be customized. Some support for fontifying definitions. -;; (I'm not convinced the faces should be customizable -- fontlock -;; faces are normally expected to be consistent.) -;; -;; Version 1.2: -;; Added support for LaTeX-style literate scripts. Allow whitespace -;; after backslash to end a line for string continuations. -;; -;; Version 1.1: -;; Use own syntax table. Use backquote (neater). Stop ''' being -;; highlighted as quoted character. Fixed `\"' fontification bug -;; in comments. -;; -;; Version 1.0: -;; Brought over from PureScript mode v1.1. - ;;; Code: (require 'font-lock) From 4e94b7d5a337ab7e491410c760b3c71f1e4c4e60 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 15:56:25 +0700 Subject: [PATCH 70/99] purescript-mode.el: make purescript-literate truly buffer-local It was defined with `defvar` and then made into buffer-local with (make-variable-buffer-local). The call though was only executed once, which is likely an omission as even the documentation states the variable supposed to be buffer-local. So fix that and make it truly buffer-local. --- purescript-mode.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index dd18942..b7b12d5 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -102,7 +102,7 @@ sure all purescript customize definitions have been loaded." (customize-browse 'purescript)) ;; Are we looking at a literate script? -(defvar purescript-literate nil +(defvar-local purescript-literate nil "*If not nil, the current buffer contains a literate PureScript script. Possible values are: `bird' and `tex', for Bird-style and LaTeX-style literate scripts respectively. Set by `purescript-mode' and @@ -110,7 +110,6 @@ literate scripts respectively. Set by `purescript-mode' and not contain either \"\\begin{code}\" or \"\\end{code}\" on a line on its own, nor does it contain \">\" at the start of a line -- the value of `purescript-literate-default' is used.") -(make-variable-buffer-local 'purescript-literate) (put 'purescript-literate 'safe-local-variable 'symbolp) ;; Default literate style for ambiguous literate buffers. (defcustom purescript-literate-default 'bird From 9412ed0d9092238dc4c4f4d432e94edcd4706fce Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 16:50:57 +0700 Subject: [PATCH 71/99] purescript-indent.el: make purescript-indent-mode truly buffer-local It was defined with `defvar` and then made into buffer-local with (make-variable-buffer-local). The call though was only executed once, which is likely an omission. Fix that and make it truly buffer-local. --- purescript-indent.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/purescript-indent.el b/purescript-indent.el index 05a1c34..250e6d3 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -1486,9 +1486,8 @@ One indentation cycle is used." ;;; purescript-indent-mode -(defvar purescript-indent-mode nil +(defvar-local purescript-indent-mode nil "Non-nil if the semi-intelligent PureScript indentation mode is in effect.") -(make-variable-buffer-local 'purescript-indent-mode) (defvar purescript-indent-map (let ((map (make-sparse-keymap))) From 7ec3407c11d171475d44279774f46a50d06f634f Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 16:42:19 +0700 Subject: [PATCH 72/99] Export purescript-literate from a shared location This gets rid of repeated "defvar"s in different files by instead importing the variable from a shared location. --- Makefile | 1 + purescript-font-lock.el | 3 +-- purescript-indent.el | 3 +-- purescript-indentation.el | 2 +- purescript-mode.el | 11 +---------- purescript-vars.el | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 purescript-vars.el diff --git a/Makefile b/Makefile index 3740ef0..71a73de 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ ELFILES = \ purescript-utils.el \ purescript-decl-scan.el \ purescript-yas.el \ + purescript-vars.el \ tests/purescript-sort-imports-tests.el \ tests/purescript-indentation-tests.el \ tests/purescript-font-lock-tests.el \ diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 77f9bae..63a636e 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -69,6 +69,7 @@ (require 'font-lock) (require 'cl-lib) +(require 'purescript-vars) (defcustom purescript-font-lock-prettify-symbols-alist `(("/\\" . ,(decode-char 'ucs #X2227)) @@ -263,8 +264,6 @@ Returns keywords suitable for `font-lock-keywords'." :type 'boolean :group 'purescript) -(defvar purescript-literate) - (defun purescript-syntactic-face-function (state) "`font-lock-syntactic-face-function' for PureScript." (cond diff --git a/purescript-indent.el b/purescript-indent.el index 250e6d3..c21b265 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -88,11 +88,10 @@ ;;; Code: +(require 'purescript-vars) (require 'purescript-string) (require 'cl-lib) -(defvar purescript-literate) - (defgroup purescript-indent nil "PureScript indentation." :group 'purescript diff --git a/purescript-indentation.el b/purescript-indentation.el index a48a726..be3e62e 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -34,6 +34,7 @@ (require 'syntax) (require 'cl-lib) +(require 'purescript-vars) (defvar delete-active-region) @@ -47,7 +48,6 @@ (defvar parse-line-number) (defvar possible-indentations) (defvar indentation-point) -(defvar purescript-literate) (defgroup purescript-indentation nil "PureScript indentation." diff --git a/purescript-mode.el b/purescript-mode.el index b7b12d5..aca85a2 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -34,6 +34,7 @@ (require 'dabbrev) (require 'compile) (require 'outline) +(require 'purescript-vars) (require 'purescript-align-imports) (require 'purescript-sort-imports) (require 'purescript-string) @@ -101,16 +102,6 @@ sure all purescript customize definitions have been loaded." purescript-yas)) (customize-browse 'purescript)) -;; Are we looking at a literate script? -(defvar-local purescript-literate nil - "*If not nil, the current buffer contains a literate PureScript script. -Possible values are: `bird' and `tex', for Bird-style and LaTeX-style -literate scripts respectively. Set by `purescript-mode' and -`literate-purescript-mode'. For an ambiguous literate buffer -- i.e. does -not contain either \"\\begin{code}\" or \"\\end{code}\" on a line on -its own, nor does it contain \">\" at the start of a line -- the value -of `purescript-literate-default' is used.") -(put 'purescript-literate 'safe-local-variable 'symbolp) ;; Default literate style for ambiguous literate buffers. (defcustom purescript-literate-default 'bird "Default value for `purescript-literate'. diff --git a/purescript-vars.el b/purescript-vars.el new file mode 100644 index 0000000..8417113 --- /dev/null +++ b/purescript-vars.el @@ -0,0 +1,33 @@ +;;; purescript-vars.el --- Variable definitions for PureScript Mode -*- lexical-binding: t -*- + +;; Author: 1997-1998 Graeme E Moss +;; 1997-1998 Tommy Thorn +;; 2003 Dave Love +;; 2025 Konstantin Kharlamov + +;; This file is not part of GNU Emacs. + +;; This file 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, or (at your option) +;; any later version. + +;; This file 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 . + +(defvar-local purescript-literate nil + "If not nil, the current buffer contains a literate PureScript script. +Possible values are: `bird' and `tex', for Bird-style and LaTeX-style +literate scripts respectively. Set by `purescript-mode' and +`literate-purescript-mode'. For an ambiguous literate buffer -- i.e. does +not contain either \"\\begin{code}\" or \"\\end{code}\" on a line on +its own, nor does it contain \">\" at the start of a line -- the value +of `purescript-literate-default' is used.") +(put 'purescript-literate 'safe-local-variable 'symbolp) + +(provide 'purescript-vars) From cd2ee96628677b3fde08dab96bdb9f107c7391f7 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 17:26:27 +0700 Subject: [PATCH 73/99] purescript-font-lock.el: assume purescript-literate is always bound Now that it's exported from a common location, there's no reason it shouldn't be (besides a bug of course). --- purescript-font-lock.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 63a636e..8899bc2 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -306,13 +306,13 @@ Returns keywords suitable for `font-lock-keywords'." ;;;###autoload (defun purescript-font-lock-choose-keywords () - (cl-case (bound-and-true-p purescript-literate) + (cl-case purescript-literate (bird purescript-font-lock-bird-literate-keywords) ((latex tex) purescript-font-lock-latex-literate-keywords) (t purescript-font-lock-keywords))) (defun purescript-font-lock-choose-syntactic-keywords () - (cl-case (bound-and-true-p purescript-literate) + (cl-case purescript-literate (bird purescript-bird-syntactic-keywords) ((latex tex) purescript-latex-syntactic-keywords) (t purescript-basic-syntactic-keywords))) From d2111a77a5f1b050a0a74939c5146d68d070df9d Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 16:55:21 +0700 Subject: [PATCH 74/99] purescript-mode.el: remove unused eldoc-print-current-symbol-info-function --- purescript-mode.el | 2 -- 1 file changed, 2 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index aca85a2..4257794 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -279,8 +279,6 @@ details." turn-on-purescript-simple-indent turn-on-purescript-unicode-input-method)) -(defvar eldoc-print-current-symbol-info-function) - ;; The main mode functions ;;;###autoload (define-derived-mode purescript-mode prog-mode "PureScript" From e3862d04e2a2e3a0e95aca99996dd7ea80e3b4ab Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 16:57:10 +0700 Subject: [PATCH 75/99] purescript-indentation.el: rm defvar for delete-active-region All supported Emacs versions have the variable, so no need to have it defined still. --- purescript-indentation.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index be3e62e..3662c85 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -34,10 +34,9 @@ (require 'syntax) (require 'cl-lib) +(require 'simple) (require 'purescript-vars) -(defvar delete-active-region) - ;; Dynamically scoped variables. (defvar following-token) (defvar current-token) From 029c1509d2b0876e004dd2e7d9e1ae73bb8ac636 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 17:03:26 +0700 Subject: [PATCH 76/99] purescript-indentation.el: group together all internal defvars --- purescript-indentation.el | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 3662c85..6a84507 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -37,7 +37,7 @@ (require 'simple) (require 'purescript-vars) -;; Dynamically scoped variables. +;; Dynamically scoped internal variables. (defvar following-token) (defvar current-token) (defvar left-indent) @@ -47,6 +47,7 @@ (defvar parse-line-number) (defvar possible-indentations) (defvar indentation-point) +(defvar purescript-indent-last-position) (defgroup purescript-indentation nil "PureScript indentation." @@ -117,9 +118,6 @@ (define-key keymap [?\C-d] 'purescript-indentation-delete-char) keymap)) -;; Used internally -(defvar purescript-indent-last-position) - ;;;###autoload (define-minor-mode purescript-indentation-mode "PureScript indentation mode that deals with the layout rule. From e23a52893b830d8165c02b594cbe3602f9f9757b Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 17:06:03 +0700 Subject: [PATCH 77/99] purescript-indentation.el: simplify localizing indent-last-position --- purescript-indentation.el | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 6a84507..4faeab3 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -47,7 +47,7 @@ (defvar parse-line-number) (defvar possible-indentations) (defvar indentation-point) -(defvar purescript-indent-last-position) +(defvar-local purescript-indent-last-position nil) (defgroup purescript-indentation nil "PureScript indentation." @@ -133,9 +133,7 @@ autofill-mode." (set (make-local-variable 'indent-line-function) 'purescript-indentation-indent-line) (set (make-local-variable 'normal-auto-fill-function) - 'purescript-indentation-auto-fill-function) - (set (make-local-variable 'purescript-indent-last-position) - nil))) + 'purescript-indentation-auto-fill-function))) ;;;###autoload (defun turn-on-purescript-indentation () From a4434b5095b396b616248eb7f40ade0b8e479fd1 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 17:14:41 +0700 Subject: [PATCH 78/99] purescript-indentation.el: replace killing/make-local with just setq-local There's no reason for killing (I even checked other major modes), and the make-local-variable may be replaced by just setq-local. --- purescript-indentation.el | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index 4faeab3..ddfef9e 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -126,14 +126,12 @@ set and deleted as if they were real tabs. It supports autofill-mode." :lighter " Ind" :keymap purescript-indentation-mode-map - (kill-local-variable 'indent-line-function) - (kill-local-variable 'normal-auto-fill-function) (when purescript-indentation-mode (setq max-lisp-eval-depth (max max-lisp-eval-depth 600)) ;; set a higher limit for recursion - (set (make-local-variable 'indent-line-function) - 'purescript-indentation-indent-line) - (set (make-local-variable 'normal-auto-fill-function) - 'purescript-indentation-auto-fill-function))) + (setq-local indent-line-function + #'purescript-indentation-indent-line) + (setq-local normal-auto-fill-function + #'purescript-indentation-auto-fill-function))) ;;;###autoload (defun turn-on-purescript-indentation () From d31134c0b23aa339c4707c3f96b5c5c134d81c69 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 10 May 2025 17:29:44 +0700 Subject: [PATCH 79/99] purescript-mode.el: remove warning about purescript-font-lock-symbols It's been there since 2019 and the variable has been no-op since then as well. I think it's fair to assume anyone who were still using the variable either moved on, or if they didn't notice anything, they will probably keep not noticing anything, because the variable has been no-op for so long. --- purescript-mode.el | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index 4257794..e1218cb 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -325,10 +325,7 @@ see documentation for that variable for more details." (setq-local beginning-of-defun-function 'purescript-beginning-of-defun) (setq prettify-symbols-alist purescript-font-lock-prettify-symbols-alist ;; make (ff-find-other-file) find .js FFI file, given .purs - ff-other-file-alist '((".purs\\'" (".js")))) - (when (bound-and-true-p purescript-font-lock-symbols) - (warn "`purescript-font-lock-symbols' is obsolete: please enable `prettify-symbols-mode' locally or globally instead.")) - ) + ff-other-file-alist '((".purs\\'" (".js"))))) (defun purescript-fill-paragraph (justify) (save-excursion From 861e13dc500585ecb8eadde46c395e9392cc8b0b Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Fri, 9 May 2025 12:24:19 +0700 Subject: [PATCH 80/99] purescript-font-lock.el: highlight docstrings unconditionally The variable was introduced to avoid highlighting docstrings for Emacs versions where `font-lock-doc-face` didn't exist, that is prior to 21. It's a variable from very old times and nowadays we support Emacs 25.1+ which has font-lock-doc-face. So remove the variable and the condition. For the safe case I did search over Github, and the variable isn't mentioned anywhere except the literal copies of the font-lock.el file. --- purescript-font-lock.el | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/purescript-font-lock.el b/purescript-font-lock.el index 8899bc2..7e804c6 100644 --- a/purescript-font-lock.el +++ b/purescript-font-lock.el @@ -259,11 +259,6 @@ Returns keywords suitable for `font-lock-keywords'." ("^\\(\\\\\\)end{code}$" 1 "!")) purescript-basic-syntactic-keywords)) -(defcustom purescript-font-lock-docstrings (boundp 'font-lock-doc-face) - "If non-nil try to highlight docstring comments specially." - :type 'boolean - :group 'purescript) - (defun purescript-syntactic-face-function (state) "`font-lock-syntactic-face-function' for PureScript." (cond @@ -285,10 +280,9 @@ Returns keywords suitable for `font-lock-keywords'." ;; https://github.com/purescript/documentation/blob/master/language/Syntax.md ;; IOW, given a `-- | foo' line followed by `-- bar' line, the latter is a ;; plain comment. - ((and purescript-font-lock-docstrings - (save-excursion - (goto-char (nth 8 state)) - (looking-at "\\(--\\|{-\\)[ \\t]*[|^]"))) + ((save-excursion + (goto-char (nth 8 state)) + (looking-at "\\(--\\|{-\\)[ \\t]*[|^]")) 'font-lock-doc-face) (t 'font-lock-comment-face))) From a2376bad60b94085723075b637a8f3c5e01fc1c0 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 19 May 2025 01:37:18 +0300 Subject: [PATCH 81/99] purescript-yas.el: remove ghc-related variable GHC isn't a thing in PureScript, it's a variable from times this was a "haskell-mode". Remove it. --- purescript-yas.el | 6 ------ 1 file changed, 6 deletions(-) diff --git a/purescript-yas.el b/purescript-yas.el index a531e73..db8c251 100644 --- a/purescript-yas.el +++ b/purescript-yas.el @@ -33,12 +33,6 @@ :group 'purescript :prefix "purescript-yas-") -(defcustom purescript-yas-ghc-language-pragmas - (split-string (shell-command-to-string "ghc --supported-extensions")) - "List of language pragmas supported by the installed version of GHC." - :group 'purescript-yas - :type '(repeat string)) - (defcustom purescript-yas-completing-function 'completing-read "Function to use for completing among alternatives." :group 'purescript-yas From 9951d9cae88139b1b3ee2b40f0c82e726fa8a1da Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 19 May 2025 22:14:12 +0300 Subject: [PATCH 82/99] Remove NEWS file with a function that referred to it The file contains no development history of the mode. The last commit that modified it was the bulk-renaming of Haskell to PureScript, so not a single entry there belongs to purescript-mode. There was also a function for opening the file (autoloaded even), remove it as well. --- Makefile | 2 +- NEWS | 408 --------------------------------------------- purescript-mode.el | 10 -- 3 files changed, 1 insertion(+), 419 deletions(-) delete mode 100644 NEWS diff --git a/Makefile b/Makefile index 71a73de..5935b54 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ ELFILES = \ ELCFILES = $(ELFILES:.el=.elc) AUTOLOADS = purescript-mode-autoloads.el -PKG_DIST_FILES = $(ELFILES) logo.svg NEWS purescript-mode.info dir +PKG_DIST_FILES = $(ELFILES) logo.svg purescript-mode.info dir PKG_TAR = purescript-mode-$(VERSION).tar %.elc: %.el diff --git a/NEWS b/NEWS deleted file mode 100644 index a00be01..0000000 --- a/NEWS +++ /dev/null @@ -1,408 +0,0 @@ -PureScript Mode NEWS -*- org -*- - -This file uses Org mode. Some useful (default) key-bindings: - - Use "C-c C-n"/"C-c C-p" to jump to next/prev heading - - Use "" to expand/collapse nodes - - Use "" to cycle visibility of all nodes - - Use "C-c C-o" to open links - -* Changes in 13.10 - -- Small fix for purescript-simple-indent: Certain indentation situations - cause valname-string to be nil, which purescript-trim did not handle - gracefully (naturally, since nil != ""). - -- Luke Hoersten's Shnippet merged in under snippets/. - -- purescript-presentation-mode is now a purescript-mode derived mode. - -- Small improvement to purescript-process-do-info (works on constructors - now and underscored names). - -- Add purescript-indent-spaces configuration variable. - -- The command string to run cabal commands is slightly more - configurable. See: C-h f purescript-process-do-cabal-format-string - -* Changes in 13.8 - -See also [[https://github.com/purescript/purescript-mode/compare/v13.07...v13.08][detailed Git history]]. - -- Make `purescript-simple-indent-mode' a proper minor mode with `SInd` as - mode-line lighter - -- Support popular "λ> " prompt in inf-purescript by default - -- Hide internal `*print-purescript-mode*' buffers - (used when `purescript-interactive-mode-eval-mode' is active) - -- Add tab-completion support for purescript-interactive-mode - (requires `:complete' command support in GHCi) - -- Add support to `purescript-process-do-info` to perform `:browse!` query - on module name when called on import statement line - -- `purescript-decl-scan-mode': - - New customize group `purescript-decl-scan' - - New flag `purescript-decl-scan-bindings-as-variables' for controlling - whether to put value bindings into the "Variables" category. - - New flag `purescript-decl-scan-add-to-menubar' for controlling - whether to add "Declarations" menu entry to menu bar. - - New manual section node `(purescript-mode)purescript-decl-scan-mode' - -- Add support for [[http://www.purescript.org/ghc/docs/latest/html/users_guide/syntax-extns.html#lambda-case][LambdaCase]] syntax extension to `purescript-indentation` - -- Change `purescript-indentation-mode' to never jump back a whole line - when pressing DEL. The old behavior can be restored by setting - `purescript-indentation-delete-backward-jump-line' to t - -- New convenience function `purescript-cabal-visit-file' for locating and - visiting most likely `.cabal` file associated with current buffer - -- Add support for [[http://www.purescript.org/ghc/docs/latest/html/users_guide/syntax-extns.html#package-import][PackageImports]] and [[http://www.purescript.org/ghc/docs/latest/html/users_guide/syntax-extns.html#safe-imports-ext][SafePureScript]] syntax extensions to - `purescript-decl-scan-mode' parser - -- Add `turn-{on,off}-purescript-doc' commands as aliases for the existing - `turn-{on,off}-purescript-doc-mode' commands - -- Add support for "cabal repl" process type to `purescript-interactive-mode' - -- Add new PureScript compilation sub-mode and associated `purescript-compile' - command - -* Changes in 13.7 - -See also [[https://github.com/purescript/purescript-mode/compare/v13.06...v13.07][detailed Git history]]. - -- Convert NEWS (this file) to Org mode style and include NEWS file in - package and add command for visiting NEWS file - (M-x purescript-mode-view-news) - -- Officially drop support for versions prior to Emacs 23 - -- New work-in-progress Info manual for purescript-mode - -- Remove deprecated `purescript-{hugs,ghci}' modules - -- Font-locking changes: - - Remove deprecated `turn-on-purescript-font-lock` function - - Improve font-locking of type-signatures in presence of newlines - - Use `font-lock-preprocessor-face' instead of the previously used - `font-lock-warning-face` for CPP directives - - Use `font-lock-warning-face` instead of the previously used - `font-lock-preprocessor-face` for Git merge conflict annotations. - -- Improvements to `purescript-move-nested' module: - - Add support for operating on active regions - - New interactive commands `purescript-move-nested-{left,right}` which - support numeric prefix arguments for controlling the amount of - shifting to apply. - -- Add `purescript-unicode-input-method.el` to distribution - (enable with `turn-on-purescript-unicode-input-method`) - -- Fix all byte-compilation warnings - -- Build-system: - - For in-place installation, `purescript-site-file.el' is renamed - to `purescript-mode-autoloads.el` - - Auto-generate ELPA compatible README file by extracting header of - purescript-mode.el - - New "make check" target - - Add Travis-CI build jobs for testing byte-compilation with - multiple Emacs versions - -- Reorganize customize settings - - Add new convenience function for browsing all PureScript Mode settings - (M-x purescript-customize) - - Add `:link' keywords pointing to the new Info manual - - Add `:group' keywords to modes to make (M-x customize-mode) work - - Create new customization groups `purescript-interactive' and `inferior-purescript' - to clean up namespace - - Create new customization group `ghc-core` containing the two new - customization variables `ghc-core-program` and `ghc-core-program-args`. - -- Improvements to purescript-interactive-mode - - Add support for deleting compile messages superseded by recompile/reloads - (M-x customize-variable RET purescript-interactive-mode-delete-superseded-errors) - - Fix `C-u M-x purescript-process-do-type` inserting bad signatures - - Integrate with Emacs' `next-error` subsystem - - Add "C-c C-f" binding to REPL keymap for enabling `next-error-follow-minor-mode' - - Add support for `-ferror-spans`-style compile messages - - Add `-ferror-spans` as default for `purescript-process-args-ghci` - - Add optional argument to - `purescript-session-{all,installed,project}-modules' to suppress - session-creation. This is useful for yasnippet usage, see commit - 517fd7e for an example. - - Change default for `purescript-process-path-ghci` to a static "ghci" - - Fix `purescript-interactive-switch` not selecting the REPL window - - Make `*purescript-process-log*` buffer configurable - (controlled via new `purescript-process-log` customize option) - -* Changes in 13.6 - -See also [[https://github.com/purescript/purescript-mode/compare/2_9_1...v13.06][detailed Git history]]. - -- Switch to new versioning scheme - -- Switch to MELPA/Marmalade based packaging - -- Cleanup/refactor build-system - -- Enhance `M-x purescript-version` to report more detailed versioning - information - -- Make purescript-interactive-mode emulate comint/eshell history navigation - (see commit 0e96843 for more details) - -- Improvements to purescript-interactive-mode - - Improve killing/restarting purescript-interactive sessions - - Improve directory prompting and resolution - - Fix redundant-import suggest trigger to support qualified imports - - Detect all abbreviations of an user-inputted ":quit" - - Fix regexps for recent GHC 7.x compiler messages - - Customizable commandline args for GHCi - (M-x customize-variable RET purescript-process-args-ghci) - - New command to load or reload via prefix argument - (M-x purescript-process-load-or-reload) - - Fix purescript-interactive-mode prompt detection - - Add cabal-ghci as supported process mode - - Add a customization option for the visibility of multi-line errors - (M-x customize-variable RET purescript-interactive-mode-hide-multi-line-errors) - -- Add forward declarations to reduce Elisp bytecompile warnings - -- Improvements to `purescript-indentation` - - Add support for the UnicodeSyntax tokens `→`, `←`, and `∷`. - - Indent "=" following data/type/newtype declarations. - - Align "->"/"→" arrows in types under "::"/"∷" - - Make customizable whether "" deletes indentation too - (via `purescript-indentation-delete-backward-indentation` and - `purescript-indentation-delete-indentation`) - - Properly indent 'rec' keyword, same as 'mdo' - - Minor optimizations. - -- Add support for "'"-prefixed constructors (-> DataKinds) to font-locking - -- New experimental purescript session menu mode (M-x purescript-menu) - -- Various minor cleanups/fixes/improvements... - -* Changes in 2.9.1 - -See also [[https://github.com/purescript/purescript-mode/compare/2_9_0...2_9_1][detailed Git history]]. - -- Bugfix release adding missing autoload declaration - -* Changes in 2.9.0 - -See also [[https://github.com/purescript/purescript-mode/compare/2_8_0...2_9_0][detailed Git history]]. - -- This is the first release after purescript-mode was migrated to GitHub - -- New experimental `purescript-interactive-mode' module implementing a - new REPL interaction mode for GHCi sessions to eventually replace - the existing "inf-purescript" mode. - -- New `purescript-process-cabal' command for interaction with cabal-install - -- New `purescript-checkers' module - -- Update purescript-cabal-mode font-lock keywords - -- Improve scrolling of hoogle output (purescript-mode.el) - -- Derive `purescript-mode` from `prog-mode` for Emacs 24+ - -- Add new binding for "" to purescript-mode's keymap which - unindents current line - -- New modules `purescript-navigate-imports`, `purescript-sort-imports' and - `purescript-align-imports' for operating on module import lines in - PureScript source code - -- Add new binding for "C-c C-." to purescript-mode's keymap to sort and - realign PureScript module imports - -- Add new binding for "C-c i" to purescript-mode's keymap to jump back and - forth from/to the current PureScript module's module import section. - -- New `inferior-purescript-kind' function for querying kind via GHCi's ":kind" - -- New `inferior-purescript-send-decl' for sending declarations to GHCi - (bound to "C-x C-d" by default) - -- Add new `purescript-doc-use-inf-purescript` customization variable - -- Add support for bird-style literate purescript editing and a new - related customization variable - `purescript-indentation-birdtrack-extra-space' - -- Font locking improvements - - Add support for Git's merge annotation - (with `font-lock-preprocessor-face') - - Improve `import', `foreign import' and `foreign export' font - locking - - Add support for `rec', `proc' and `mdo` as keywords - - Make whitespace within `-- |' and `{- |' optional when possible - -- New `purescript-move-nested` module providing utilities for - interactively {in,de}denting nested "hanging" blocks. - -- Add stylish-purescript support - (enable via `purescript-stylish-on-save` customization variable) - -- Add support for generating tags on save - (enable via `purescript-tags-on-save' customization variable) - -- Set sensible dabbrev defaults in purescript-mode - -- Added `SCC` pragma insert/delete commands - (`purescript-mode-insert-scc-at-point` and `purescript-mode-kill-scc-at-point') - -- New experimental `purescript-mode-contextual-space' command - -- And a couple more cleanups/fixes/improvements... - -* Changes in 2.8.0 (since 2.7.0) - -See also [[https://github.com/purescript/purescript-mode/compare/2_7_0...2_8_0][detailed Git history]]. - -- Minimal indentation support for arrow syntax - -- Avoid opening a new inf-purescript window if one is already visible. - Windows on other virtual desktops or iconified frames don't count. - -- Force comint-process-echoes to nil - -- Autolaunch purescript-mode for files starting with #!/usr/bin/runghc - and similar - -- Added minimal major mode for parsing GHC core files, courtesy of Johan Tibell. - There is a corresponding PureScript menu entry. - -- Allow configuration of where-clause indentation; M-x customize-group - purescript-indentation. - -* Changes since 2.6.4 - -- fill-paragraph (M-q) now only affects comments, and correctly - handles Haddock commentary. adaptive-fill-mode is turned off, as it - was interfering. - -- Yet more unicode symbols - -- Better support for unicode encoding of purescript source files - -- mdo correctly indented - -- Indentation fixes, fixes to the fixes, and fixes to the fixes to the - fixes - -- New command: M-x purescript-check, calls (by default) hlint on the - current file. Also bound to C-c C-v. - - You can also use the flymake minor mode with this. - -* Changes since 2.5.1 - -- Parser corrections for purescript-indentation and purescript-decl-scan - -- purescript-indentation: Pressing tab in the rightmost position now - moves to the leftmost, by default with a warning. - -- Typo fix: One purescript-indentation variable had ended up in the - purescript-ntation customize group. - -- purescript-hoogle aliased to hoogle, purescript-hayoo aliased to hayoo - -- Courtesy of Alex Ott: - - Additional unicode symbols for font-lock-symbols: () == /= >= <= !! && || sqrt - - M-x purescript-hayoo search added, opens using browse-url - - Bug-fix for inferior-purescript-type - -- If purescript-indentation errors out, it now fail-safes to inserting - a literal newline or deleting one character, for return and - backspace respectively. - -* Changes since 2.4: - -- purescript-indentation, a new minor mode for indentation. - -* Changes since 2.3: - -- Update license to GPLv3. - -- New derived major mode for .pursc files. - -- Removed the C-c C-r binding to reload a file. You can still call - inferior-purescript-reload-file (and/or bind it to your favorite key, - including C-c C-r) or you can now use C-u C-c C-l. - -- C-c C-d looks up the symbol at point in the Haddock docs. - -- Haddock comments are highlighted with font-lock-doc-face if it exists. - -- Use `tex' rather than `latex' for purescript-literate. - -- inf-purescript.el tries to find the root of the module hierarchy to determine - the root of a project (either by looking for a Cabal file or relying on - the `module' declaration line). If all works well, this will make C-c C-l - automatically switch to the root dir, so that dependencies in other - directories are automatically found. If it doesn't, complain and/or set - inferior-purescript-find-project-root to nil. - -- The new command purescript-hoogle helps you query Hoogle from Emacs. - -* Changes since 2.2: - -- Trivial support for Cabal package description files. - -- Minor bug fixes. - -* Changes since 2.1: - -- There are now commands to find type and info of identifiers by querying an - inferior purescript process. Available under C-c C-t, C-c C-i, and C-c M-. - -- Indentation now looks back further, until a line that has no indentation. - To recover the earlier behavior of stopping at the first empty line - instead, configure purescript-indent-look-past-empty-line. - -- inf-purescript can wait until a file load completes and jump directly to the - first error, like purescript-ghci and purescript-hugs used to do. See the var - inferior-purescript-wait-and-jump. - -* Changes since 2.0: - -- inf-purescript uses ghci if hugs is absent. - -- Fix up some binding conflicts (C-c C-o in purescript-doc) - -- Many (hopefully minor) changes to the indentation. - -- New symbols in purescript-font-lock-symbols-alist. - -* Changes since 1.45: - -- keybindings C-c have been replaced by C-c C- so as not - to collide with minor modes. - -- The following modules are now automatically activated without having to - add anything to purescript-mode-hook: - purescript-font-lock (just turn on global-font-lock-mode). - purescript-decl-scan (just bind `imenu' to some key). - -- In recent Emacsen, purescript-doc hooks into eldoc-mode. - -- purescript-hugs and purescript-ghci are superceded by inf-purescript. - -- Indentation rules have been improved when using layout inside parens/braces. - -- Symbols like -> and \ can be displayed as actual arrows and lambdas. - See purescript-font-lock-symbols. - -- Tweaks to the font-lock settings. Among other things paren-matching - with things like \(x,y) should work correctly now. - -- New maintainer . diff --git a/purescript-mode.el b/purescript-mode.el index e1218cb..f646835 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -72,16 +72,6 @@ When MESSAGE is non-nil, display a message with the version." (insert version) (message "%s" version)))) -;;;###autoload -(defun purescript-mode-view-news () - "Display information on recent changes to purescript-mode." - (interactive) - (with-current-buffer (find-file-read-only (expand-file-name "NEWS" purescript-mode-pkg-base-dir)) - (goto-char (point-min)) - (outline-hide-sublevels 1) - (outline-next-visible-heading 1) - (outline-show-subtree))) - (defgroup purescript nil "Major mode for editing PureScript programs." :link '(custom-manual "(purescript-mode)") From 09a864d116026bfa05b63d9f7b383a3bded26369 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Mon, 19 May 2025 22:20:17 +0300 Subject: [PATCH 83/99] Remove logo.svg It's a Haskell logo, from times it was a haskell-mode. --- Makefile | 2 +- logo.svg | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 logo.svg diff --git a/Makefile b/Makefile index 5935b54..efb5994 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ ELFILES = \ ELCFILES = $(ELFILES:.el=.elc) AUTOLOADS = purescript-mode-autoloads.el -PKG_DIST_FILES = $(ELFILES) logo.svg purescript-mode.info dir +PKG_DIST_FILES = $(ELFILES) purescript-mode.info dir PKG_TAR = purescript-mode-$(VERSION).tar %.elc: %.el diff --git a/logo.svg b/logo.svg deleted file mode 100644 index 401e599..0000000 --- a/logo.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - From 9b76c58c2f146509bf3d18854d26bec90f158260 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 24 May 2025 20:57:45 +0300 Subject: [PATCH 84/99] purescript-mode.el: remove unused purescript-mode-pkg-base-dir var --- purescript-mode.el | 4 ---- 1 file changed, 4 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index f646835..bc2b71c 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -51,10 +51,6 @@ (defconst purescript-git-version "@GIT_VERSION@" "The Git version of `purescript-mode'.") -(defvar purescript-mode-pkg-base-dir (file-name-directory load-file-name) - "Package base directory of installed `purescript-mode'. -Used for locating additional package data files.") - ;;;###autoload (defun purescript-version (&optional here) "Show the `purescript-mode` version in the echo area. From 915cd2c2e569aed92c6b5d2dbf64d802dc8bf33d Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 24 May 2025 20:58:19 +0300 Subject: [PATCH 85/99] purescript-mode.el: remove unused purescript-completing-read-function --- purescript-mode.el | 9 --------- 1 file changed, 9 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index bc2b71c..1bfb284 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -398,15 +398,6 @@ is asked to show extra info for the items matching QUERY.." current-prefix-arg))) (browse-url (format "https://pursuit.purescript.org/search?q=%s" query))) -(defcustom purescript-completing-read-function 'completing-read - "Default function to use for completion." - :group 'purescript - :type '(choice - (function-item :tag "completing-read" :value completing-read) - (function-item :tag "ido" :value ido-completing-read) - (function-item :tag "helm" :value helm--completing-read-default) - (function :tag "Custom function"))) - (defcustom purescript-indent-spaces 2 "Number of spaces to indent inwards." :type 'integer From 518178ba6c6789379e6b9fe45e304ce62bfd2fc2 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 25 May 2025 22:06:18 +0300 Subject: [PATCH 86/99] Replace purescript-trim with string-trim This is a common helper Emacs had for a while, no need to keep our own function. --- purescript-indent.el | 7 +++++-- purescript-mode.el | 2 +- purescript-string.el | 8 -------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/purescript-indent.el b/purescript-indent.el index c21b265..31cf2c4 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -91,6 +91,9 @@ (require 'purescript-vars) (require 'purescript-string) (require 'cl-lib) +(eval-when-compile + (when (< emacs-major-version 28) + (require 'subr-x))) (defgroup purescript-indent nil "PureScript indentation." @@ -655,8 +658,8 @@ symbols in the sexp." (string-match "where[ \t]*" purescript-indent-current-line-first-ident)) (diff-first ; not a function def with the same name (or (null valname-string) - (not (string= (purescript-trim valname-string) - (purescript-trim purescript-indent-current-line-first-ident))))) + (not (string= (string-trim valname-string) + (string-trim purescript-indent-current-line-first-ident))))) ;; (is-type-def ;; (and rpurs-sign (eq (char-after rpurs-sign) ?\:))) diff --git a/purescript-mode.el b/purescript-mode.el index f646835..0bb61bf 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -439,7 +439,7 @@ Brings up the documentation for purescript-mode-hook." (message "%s" (concat (car lines) (if (and (cdr lines) (stringp (cadr lines))) - (format " [ %s .. ]" (purescript-string-take (purescript-trim (cadr lines)) 10)) + (format " [ %s .. ]" (purescript-string-take (string-trim (cadr lines)) 10)) "")))))) (defun purescript-current-line-string () diff --git a/purescript-string.el b/purescript-string.el index 23af498..9270385 100644 --- a/purescript-string.el +++ b/purescript-string.el @@ -1,12 +1,4 @@ ;;; purescript-string.el --- string manipulation utilties -*- lexical-binding: t -*- -;;;###autoload -(defun purescript-trim (string) - (replace-regexp-in-string - "^[ \t\n]+" "" - (replace-regexp-in-string - "[ \t\n]+$" "" - string))) - ;;;###autoload (defun purescript-string-take (string n) "Take n chars from string." From 8144869f4802b1c5ceff0f3e3e157b63d94ab980 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 25 May 2025 22:07:43 +0300 Subject: [PATCH 87/99] Un-globalize purescript-string-take It's a small utility function used in one place, and is unlikely used by anyone else. There's no need to keep it autoloaded and in a separate file. --- purescript-mode.el | 6 ++++++ purescript-string.el | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/purescript-mode.el b/purescript-mode.el index 0bb61bf..c2f4455 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -432,6 +432,12 @@ Brings up the documentation for purescript-mode-hook." (goto-char (+ (line-beginning-position) col)))) +(defun purescript-string-take (string n) + "Take n chars from string." + (substring string + 0 + (min (length string) n))) + (defun purescript-mode-message-line (str) "Message only one line, multiple lines just disturbs the programmer." (let ((lines (split-string str "\n" t))) diff --git a/purescript-string.el b/purescript-string.el index 9270385..d8f4652 100644 --- a/purescript-string.el +++ b/purescript-string.el @@ -1,11 +1,4 @@ ;;; purescript-string.el --- string manipulation utilties -*- lexical-binding: t -*- -;;;###autoload -(defun purescript-string-take (string n) - "Take n chars from string." - (substring string - 0 - (min (length string) n))) - ;;;###autoload (defun purescript-is-prefix-of (x y) "Is x string a prefix of y string?" From baa0714c5be64deaee763e07946ee656dbeef330 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 25 May 2025 22:10:54 +0300 Subject: [PATCH 88/99] Remove purescript-string.el It has just one utility function which is unlikely being used by anyone. Remove it. --- Makefile | 1 - purescript-indent.el | 1 - purescript-mode.el | 1 - purescript-string.el | 9 --------- 4 files changed, 12 deletions(-) delete mode 100644 purescript-string.el diff --git a/Makefile b/Makefile index efb5994..d86ccf9 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,6 @@ ELFILES = \ purescript-simple-indent.el \ purescript-sort-imports.el \ purescript-str.el \ - purescript-string.el \ purescript-unicode-input-method.el \ purescript-utils.el \ purescript-decl-scan.el \ diff --git a/purescript-indent.el b/purescript-indent.el index 31cf2c4..fe0b490 100644 --- a/purescript-indent.el +++ b/purescript-indent.el @@ -89,7 +89,6 @@ ;;; Code: (require 'purescript-vars) -(require 'purescript-string) (require 'cl-lib) (eval-when-compile (when (< emacs-major-version 28) diff --git a/purescript-mode.el b/purescript-mode.el index c2f4455..a181651 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -37,7 +37,6 @@ (require 'purescript-vars) (require 'purescript-align-imports) (require 'purescript-sort-imports) -(require 'purescript-string) (require 'purescript-font-lock) (require 'cl-lib) (cl-eval-when 'compile (require 'find-file)) diff --git a/purescript-string.el b/purescript-string.el deleted file mode 100644 index d8f4652..0000000 --- a/purescript-string.el +++ /dev/null @@ -1,9 +0,0 @@ -;;; purescript-string.el --- string manipulation utilties -*- lexical-binding: t -*- -;;;###autoload -(defun purescript-is-prefix-of (x y) - "Is x string a prefix of y string?" - (string= x (substring y 0 (min (length y) (length x))))) - -(defun purescript-string ()) - -(provide 'purescript-string) From 9a03d7573c75e01d6f9b413ebb0082bf4f706c7f Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sun, 25 May 2025 23:25:03 +0300 Subject: [PATCH 89/99] Remove purescript-str module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file is another legacy from Haskell-mode. It contains no autoloaded or interactive (i.e. ones somebody could bind to a hotkey) functions, and the module isn't used anywhere in the code. Some of the functions are specific to Haskell — for example, `purescript-str-trim` mentions some "PureScript Report", which actually refers to Haskell report (when the mode was imported from Haskell, code was batch-renamed from haskell to purescript). So there's no point to prefer purescript-str-trim to plain string-trim. Thus, let's just remove the module from the codebase. --- Makefile | 3 - purescript-str.el | 180 ---------------------------------- tests/purescript-str-tests.el | 114 --------------------- 3 files changed, 297 deletions(-) delete mode 100644 purescript-str.el delete mode 100644 tests/purescript-str-tests.el diff --git a/Makefile b/Makefile index d86ccf9..fabfde3 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,6 @@ ELFILES = \ purescript-presentation-mode.el \ purescript-simple-indent.el \ purescript-sort-imports.el \ - purescript-str.el \ purescript-unicode-input-method.el \ purescript-utils.el \ purescript-decl-scan.el \ @@ -28,7 +27,6 @@ ELFILES = \ tests/purescript-sort-imports-tests.el \ tests/purescript-indentation-tests.el \ tests/purescript-font-lock-tests.el \ - tests/purescript-str-tests.el ELCFILES = $(ELFILES:.el=.elc) AUTOLOADS = purescript-mode-autoloads.el @@ -48,7 +46,6 @@ compile: $(ELCFILES) test: compile @$(BATCH) -l tests/purescript-sort-imports-tests.elc \ - -l tests/purescript-str-tests.elc \ -l tests/purescript-indentation-tests.elc \ -l tests/purescript-font-lock-tests.elc \ -f ert-run-tests-batch-and-exit diff --git a/purescript-str.el b/purescript-str.el deleted file mode 100644 index 8f6c3a3..0000000 --- a/purescript-str.el +++ /dev/null @@ -1,180 +0,0 @@ -;;; purescript-str.el --- PureScript related string utilities -*- lexical-binding: t -*- - -;; Copyright (C) 2013 Herbert Valerio Riedel - -;; Author: Herbert Valerio Riedel - -;; This file is not part of GNU Emacs. - -;; This file 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 file 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 . - -;;; Commentary: - -;;; Todo: - -;; - write ERT tests - -;;; Code: - -(defun purescript-str-trim (string) - "Remove whitespace around STRING. - -A Whitespace character is defined in the PureScript Report as follows - - whitechar -> newline | vertab | space | tab | uniWhite - newline -> return linefeed | return | linefeed | formfeed - uniWhite -> any Unicode character defined as whitespace - -Note: The implementation currently only supports ASCII - white-space characters, i.e. the implemention doesn't - consider uniWhite." - - (let ((s1 (if (string-match "[\t\n\v\f\r ]+\\'" string) (replace-match "" t t string) string))) - (if (string-match "\\`[\t\n\v\f\r ]+" s1) (replace-match "" t t s1) s1))) - -(defun purescript-str-only-spaces-p (string) - "Return t if STRING contains only whitespace (or is empty)." - (string= "" (purescript-str-trim string))) - -(defun purescript-str-take (string n) - "Return (up to) N character length prefix of STRING." - (substring string 0 (min (length string) n))) - -(defalias 'purescript-str-is-prefix-of-p 'string-prefix-p) - -(defun purescript-str-is-suffix-of-p (str1 str2 &optional ignore-case) - "Return non-nil if STR1 is a suffix of STR2. -If IGNORE-CASE is non-nil, the comparison is done without paying attention -to case differences. - -Dual to `purescript-str-is-prefix-of-p'" - (let ((pos (- (length str2) (length str1)))) - (if (>= pos 0) - (eq t (compare-strings str1 nil nil - str2 pos nil ignore-case))))) - -(defconst purescript-str-literal-encode-ascii-array - [ "\\NUL" "\\SOH" "\\STX" "\\ETX" "\\EOT" "\\ENQ" "\\ACK" "\\a" "\\b" "\\t" "\\n" "\\v" "\\f" "\\r" "\\SO" "\\SI" "\\DLE" "\\DC1" "\\DC2" "\\DC3" "\\DC4" "\\NAK" "\\SYN" "\\ETB" "\\CAN" "\\EM" "\\SUB" "\\ESC" "\\FS" "\\GS" "\\RS" "\\US" " " "!" "\\\"" "#" "$" "%" "&" "'" "(" ")" "*" "+" "," "-" "." "/" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" ":" ";" "<" "=" ">" "?" "@" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "[" "\\\\" "]" "^" "_" "`" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "{" "|" "}" "~" "\\DEL" ] - "Array of encodings for 7-bit ASCII character points indexed by ASCII value.") - -(defun purescript-str-literal-encode (str &optional no-quotes) - "Encode STR according PureScript escape rules using 7-bit ASCII representation. - -The serialization has been implement to closely match the -behaviour of GHC's Show instance for Strings. - -If NO-QUOTES is non-nil, omit wrapping result in quotes. - -This is the dual operation to `purescript-str-literal-decode'." - - (let ((lastc -1)) - (let ((encode (lambda (c) - (let ((lc lastc)) - (setq lastc c) - (if (>= c 128) ;; if non-ASCII code point - (format "\\%d" c) - ;; else, for ASCII code points - (if (or (and (= lc 14) (= c ?H)) ;; "\SO\&H" - (and (>= lc 128) (>= c ?0) (<= c ?9))) ;; "\123\&4" - (concat "\\&" (aref purescript-str-literal-encode-ascii-array c)) - (aref purescript-str-literal-encode-ascii-array c) - )))))) - - (if no-quotes - (mapconcat encode str "") - (concat "\"" (mapconcat encode str "") "\""))))) - -(defconst purescript-str-literal-escapes-regexp - (concat "[\\]\\(?:" - (regexp-opt (append - (mapcar (lambda (c) (format "%c" c)) - "abfnrtv\\\"'&") ;; "charesc" escape sequences - (mapcar (lambda (c) (format "^%c" c)) - "ABCDEFGHIJKLMNOPQRSTUVWXYZ@[\\]^_") ;; "cntrl" escape sequences - (mapcar (lambda (s) (format "%s" s)) - (split-string "NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR - SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC - FS GS RS US SP DEL")))) ;; "ascii" (w\o "cntrl") escape sequences - "\\|" "[\t\n\v\f\r ]+[\\]" ;; whitespace gaps - "\\|" "[0-9]+" ;; decimal escape sequence - "\\|" "o[0-7]+" ;; octal escape sequence - "\\|" "x[0-9a-f]+" ;; hex escape sequence - "\\)?") ;; everything else is an invalid escape sequence - "Regexp for matching escape codes in string literals. -See PureScript Report Sect 2.6, -URL `http://www.purescript.org/onlinereport/purescript2010/purescriptch2.html#x7-200002.6', -for more details.") - -(defconst purescript-str-literal-decode1-table - (let ((h (make-hash-table :test 'equal))) - (mapc (lambda (c) (puthash (concat "\\" (car c)) (cdr c) h)) - '(;; ascii-escapes - ("NUL" . "\x00") ("SOH" . "\x01") ("STX" . "\x02") ("ETX" . "\x03") ("EOT" . "\x04") ("ENQ" . "\x05") - ("ACK" . "\x06") ("BEL" . "\x07") ("BS" . "\x08") ("HT" . "\x09") ("LF" . "\x0a") ("VT" . "\x0b") - ("FF" . "\x0c") ("CR" . "\x0d") ("SO" . "\x0e") ("SI" . "\x0f") ("DLE" . "\x10") ("DC1" . "\x11") - ("DC2" . "\x12") ("DC3" . "\x13") ("DC4" . "\x14") ("NAK" . "\x15") ("SYN" . "\x16") ("ETB" . "\x17") - ("CAN" . "\x18") ("EM" . "\x19") ("SUB" . "\x1a") ("ESC" . "\x1b") ("FS" . "\x1c") ("GS" . "\x1d") - ("RS" . "\x1e") ("US" . "\x1f") ("SP" . "\x20") ("DEL" . "\x7f" ) - ;; C-compatible single-char escape sequences - ("a" . "\x07") ("b" . "\x08") ("f" . "\x0c") ("n" . "\x0a") ("r" . "\x0d") ("t" . "\x09") ("v" . "\x0b") - ;; trivial escapes - ("\\" . "\\") ("\"" . "\"") ("'" . "'") - ;; "empty" escape - ("&" . ""))) - h) - "Hash table containing irregular escape sequences and their decoded strings. -Used by `purescript-str-literal-decode1'.") - -(defun purescript-str-literal-decode1 (l) - "Decode a single string literal escape sequence. -L must contain exactly one escape sequence. -This is an internal function used by `purescript-str-literal-decode'." - (let ((case-fold-search nil)) - (cond - ((gethash l purescript-str-literal-decode1-table)) - ((string-match "\\`[\\][0-9]+\\'" l) (char-to-string (string-to-number (substring l 1) 10))) - ((string-match "\\`[\\]x[[:xdigit:]]+\\'" l) (char-to-string (string-to-number (substring l 2) 16))) - ((string-match "\\`[\\]o[0-7]+\\'" l) (char-to-string (string-to-number (substring l 2) 8))) - ((string-match "\\`[\\]\\^[@-_]\\'" l) (char-to-string (- (aref l 2) ?@))) ;; "cntrl" escapes - ((string-match "\\`[\\][\t\n\v\f\r ]+[\\]\\'" l) "") ;; whitespace gap - (t (error "Invalid escape sequence"))))) - -(defun purescript-str-literal-decode (estr &optional no-quotes) - "Decode a PureScript string-literal. -If NO-QUOTES is nil, ESTR must be surrounded by quotes. - -This is the dual operation to `purescript-str-literal-encode'." - (if (and (not no-quotes) - (string-match-p "\\`\"[^\\\"[:cntrl:]]*\"\\'" estr)) - (substring estr 1 -1) ;; optimized fast-path for trivial strings - (let ((s (if no-quotes ;; else: do general decoding - estr - (if (string-match-p "\\`\".*\"\\'" estr) - (substring estr 1 -1) - (error "String literal must be delimited by quotes")))) - (case-fold-search nil)) - (replace-regexp-in-string purescript-str-literal-escapes-regexp #'purescript-str-literal-decode1 s t t)))) - -(defun purescript-str-ellipsize (string n) - "Return STRING truncated to (at most) N characters. -If truncation occured, last character in string is replaced by `…'. -See also `purescript-str-take'." - (cond - ((<= (length string) n) string) ;; no truncation needed - ((< n 1) "") - (t (concat (substring string 0 (1- n)) "…")))) - -(provide 'purescript-str) - -;;; purescript-str.el ends here diff --git a/tests/purescript-str-tests.el b/tests/purescript-str-tests.el deleted file mode 100644 index bfd4e88..0000000 --- a/tests/purescript-str-tests.el +++ /dev/null @@ -1,114 +0,0 @@ -;; unit tests for purescript-str.el -*- lexical-binding: t -*- - -(require 'ert) - -(require 'purescript-str ) ;; implementation under test - -(ert-deftest purescript-str-take () - (should (string= (purescript-str-take "" 0) "")) - (should (string= (purescript-str-take "" 1) "")) - (should (string= (purescript-str-take "" 2) "")) - (should (string= (purescript-str-take "x" 0) "")) - (should (string= (purescript-str-take "x" 1) "x")) - (should (string= (purescript-str-take "x" 2) "x")) - (should (string= (purescript-str-take "x" 3) "x")) - (should (string= (purescript-str-take "xy" 0) "")) - (should (string= (purescript-str-take "xy" 1) "x")) - (should (string= (purescript-str-take "xy" 2) "xy")) - (should (string= (purescript-str-take "xy" 3) "xy")) - (should (string= (purescript-str-take "xyz" 0) "")) - (should (string= (purescript-str-take "xyz" 1) "x")) - (should (string= (purescript-str-take "xyz" 2) "xy")) - (should (string= (purescript-str-take "xyz" 3) "xyz")) - (should (string= (purescript-str-take "xyz" 4) "xyz"))) - -(ert-deftest purescript-str-ellipsize () - (should (string= (purescript-str-ellipsize "" 0) "")) - (should (string= (purescript-str-ellipsize "" 1) "")) - (should (string= (purescript-str-ellipsize "" 2) "")) - (should (string= (purescript-str-ellipsize "x" 0) "")) - (should (string= (purescript-str-ellipsize "x" 1) "x")) - (should (string= (purescript-str-ellipsize "x" 2) "x")) - (should (string= (purescript-str-ellipsize "x" 3) "x")) - (should (string= (purescript-str-ellipsize "xy" 0) "")) - (should (string= (purescript-str-ellipsize "xy" 1) "…")) - (should (string= (purescript-str-ellipsize "xy" 2) "xy")) - (should (string= (purescript-str-ellipsize "xy" 3) "xy")) - (should (string= (purescript-str-ellipsize "xyz" 0) "")) - (should (string= (purescript-str-ellipsize "xyz" 1) "…")) - (should (string= (purescript-str-ellipsize "xyz" 2) "x…")) - (should (string= (purescript-str-ellipsize "xyz" 3) "xyz")) - (should (string= (purescript-str-ellipsize "xyz" 4) "xyz"))) - -(ert-deftest purescript-str-literal-encode-empty () - (should (string= (purescript-str-literal-encode "") "\"\"")) - (should (string= (purescript-str-literal-encode "" t) ""))) - -(ert-deftest purescript-str-literal-decode-empty () - (dolist (s0 (list "\"\"" - "\"\\&\"" - "\"\\&\\&\\&\"" - "\"\\ \\\"" - "\"\\ \\\\ \\\"" - "\"\\&\\ \\\"" - "\"\\ \\\\&\\ \\\"")) - (should (string= "" (purescript-str-literal-decode s0))) - (should (string= "" (purescript-str-literal-decode (substring s0 1 -1) t))))) - -(ert-deftest purescript-str-literal-decode-backslash () - "Test some edge cases involving backslashes." - (dolist (cs (list (cons "\\\\" "\\") - (cons "\\x10" "\x10") - (cons "\\\\x10" "\\x10") - (cons "\\ \\x10" "x10") - (cons "\\ \\ \\x30" " 0") - (cons "\\SO\\&H" "\x0eH") - (cons "\\SOH\\&" "\x01") - (cons "\\n" "\n") - (cons "\\'" "'") - (cons "\\\"" "\"") - (cons "\\SOH" "\x01"))) - (should (string= (cdr cs) - (purescript-str-literal-decode (concat "\"" (car cs) "\"")))) - (should (string= (cdr cs) - (purescript-str-literal-decode (car cs) t))))) - -(defun purescript-str-random (n) - "Generate random N characters long string." - (let ((a ())) - (apply #'string (dotimes (_ n a) - (setq a (cons (random 1024) a)))))) - -(ert-deftest purescript-str-literal-decode-encode () - "Test whether decode+encode is the identity function." - (random t) - ;; some edge cases - (dolist (s0 (list "\x0e\x48" ;; '\SO' 'H' - "\x01" ;; '\SOH' - "\x00df\x30" ;; '\223' '0' - "'" - "\'" - "\"" - "\x0e&H" - "\\" - " \\ \\" - "\\\\\"" - (string 40 945 8322 946 8323 8743 947 178 949 178 41) - "x" - "xy" - "\\x123" - "\\ \\x123" - " " - " " - "")) - (should (string= s0 (purescript-str-literal-decode (purescript-str-literal-encode s0)))) - (should (string= s0 (purescript-str-literal-decode (purescript-str-literal-encode s0 t) t)))) - - ;; randomized testing - (dotimes (_ 500) - (dotimes (n 15) - (let* ((s0 (purescript-str-random (+ 1 n))) - (s1 (purescript-str-literal-decode (purescript-str-literal-encode s0))) - (s2 (purescript-str-literal-decode (purescript-str-literal-encode s0 t) t))) - (should (string= s0 s1)) - (should (string= s0 s2)))))) From 1d108f250755c893e93db97b2d1f3f21ba700a96 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 29 May 2025 22:43:36 +0300 Subject: [PATCH 90/99] Don't check for Haskell's "curly braces" indentation PureScript doesn't support "curly braces" mode as Haskell does, so the only thing the code did was introducing some bug where mixing let-in and case-of statements were breaking indentation. Credits to @purefunctor for the solution. Fixes: https://github.com/purescript-emacs/purescript-mode/issues/12 --- purescript-indentation.el | 4 +--- tests/purescript-indentation-tests.el | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index ddfef9e..f972bff 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -762,9 +762,7 @@ indent the current line. This has to be fixed elsewhere." (throw 'parse-end nil))))) (defun purescript-indentation-layout (parser) - (if (string= current-token "{") - (purescript-indentation-list parser "}" ";" nil) - (purescript-indentation-implicit-layout-list parser))) + (purescript-indentation-implicit-layout-list parser)) (defun purescript-indentation-expression-token (token) (member token '("if" "let" "do" "case" "\\" "(" "[" "{" "::" diff --git a/tests/purescript-indentation-tests.el b/tests/purescript-indentation-tests.el index f2dac73..0cc77b0 100644 --- a/tests/purescript-indentation-tests.el +++ b/tests/purescript-indentation-tests.el @@ -237,3 +237,29 @@ foo = do identifier :: Array String <- function call _ <- another call pure unit")) + +(ert-deftest let-in-separate-lines () + "Tests bug #12" + (purescript-test-indentation " +test1 a += let { x } = a +in x" + +" +test1 a + = let { x } = a + in x")) + +(ert-deftest case-of-separate-lines () + "Tests bug #12" + (purescript-test-indentation " +test3 a += case a of +{ x: y } +-> y" + + " +test3 a + = case a of + { x: y } + -> y")) From 0213d2c5a1a82a39c3dd63ea32275f8e7e8aa70d Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Fri, 30 May 2025 00:42:08 +0300 Subject: [PATCH 91/99] Remove utils module The module contains just 2 functions, none of which are used in the project or are interactive. Of them, `purescript-utils-parse-import-statement-at-point` contains various Haskell-specific parsing and doesn't sound useful to a common user. The `purescript-utils-read-directory-name` is just some odd wrapper for normalizing a path, and unlikely to be useful to anyone outside the project. Thus, just remove the module. --- Makefile | 1 - purescript-utils.el | 74 --------------------------------------------- 2 files changed, 75 deletions(-) delete mode 100644 purescript-utils.el diff --git a/Makefile b/Makefile index fabfde3..d3585b7 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,6 @@ ELFILES = \ purescript-simple-indent.el \ purescript-sort-imports.el \ purescript-unicode-input-method.el \ - purescript-utils.el \ purescript-decl-scan.el \ purescript-yas.el \ purescript-vars.el \ diff --git a/purescript-utils.el b/purescript-utils.el deleted file mode 100644 index 5651e87..0000000 --- a/purescript-utils.el +++ /dev/null @@ -1,74 +0,0 @@ -;;; purescript-utils.el --- General utility functions used by purescript-mode modules -*- lexical-binding: t -*- - -;; Copyright (C) 2013 Herbert Valerio Riedel - -;; Author: Herbert Valerio Riedel - -;; This file is not part of GNU Emacs. - -;; This file 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 file 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 . - -;;; Commentary: - -;; This module's purpose is to provide a place for helper functions -;; which are general enough to be usable by multiple modules and/or -;; to alleviate circular module dependency problems. -;; -;; When possible, functions in this module shall be accompanied by -;; ERT-based unit tests. -;; -;; See also `purescript-str.el' for string utility functions. -;; -;; All symbols in this module have a `purescript-utils-' prefix. - -;;; Code: - -;; NOTE: This module is supposed to be a leaf-module and shall not -;; require/depend-on any other purescript-mode modules in order to -;; stay at the bottom of the module dependency graph. - - -(defun purescript-utils-read-directory-name (prompt default) - "Read directory name and normalize to true absolute path. -Refer to `read-directory-name' for the meaning of PROMPT and -DEFAULT." - (let ((filename (file-truename - (read-directory-name prompt - default - default)))) - (concat (replace-regexp-in-string "/$" "" filename) - "/"))) - - -(defun purescript-utils-parse-import-statement-at-point () - "Return imported module name if on import statement or nil otherwise. -This currently assumes that the \"import\" keyword and the module -name are on the same line. - -This function supports the SafePureScript and PackageImports syntax extensions. - -Note: doesn't detect if in {--}-style comment." - (save-excursion - (goto-char (line-beginning-position)) - (if (looking-at (concat "[\t ]*import[\t ]+" - "\\(safe[\t ]+\\)?" ;; SafePureScript - "\\(qualified[\t ]+\\)?" - "\\(\"[^\"]*\"[\t ]+\\)?" ;; PackageImports - "\\([[:digit:][:upper:][:lower:].]+\\)")) - (match-string-no-properties 4)))) - - -(provide 'purescript-utils) - -;;; purescript-utils.el ends here From fd2050fd3cfcad37632975fc83fca0f3ffcabfce Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Fri, 30 May 2025 01:03:15 +0300 Subject: [PATCH 92/99] Be explicit about indentation mode not being enabled Currently when a new user tries indenting, that basically invokes help for the mode hook, which isn't useful and looks more like a bug than anything else. Solve this by printing an explicit explanation that a user needs to enable an indentation mode. --- README.md | 17 +++++++++++++---- purescript-mode.el | 5 ++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fd62e7f..2b1a524 100644 --- a/README.md +++ b/README.md @@ -68,10 +68,19 @@ and recommended installation method. Basic Configuration ------------------- -For setup instructions, please consult the new integrated purescript-mode -[Info](https://www.gnu.org/software/texinfo/manual/info/info.html) -manual which can be accessed after installation via -`M-x info-display-manual [RET] purescript-mode`. +PureScript mode provides multiple indentation engines, and leaves the choice up to the user. To have indentation an according indentation mode needs to be enabled. Otherwise, attempting to indent will print an error describing this. + +Minimal configuration may look something like: + +```lisp +(use-package purescript-mode + :defer t + :config + (defun myhook-purescript-mode () + (turn-on-purescript-indentation) + (add-hook 'before-save-hook #'purescript-sort-imports nil t)) + (add-hook 'purescript-mode-hook #'myhook-purescript-mode)) +``` Support ------- diff --git a/purescript-mode.el b/purescript-mode.el index 787eb9a..e24d5ce 100644 --- a/purescript-mode.el +++ b/purescript-mode.el @@ -407,7 +407,10 @@ is asked to show extra info for the items matching QUERY.." has been selected. Brings up the documentation for purescript-mode-hook." - (describe-variable 'purescript-mode-hook)) + (error + "To use indentation you need to turn-on one of the indentation modes. Please see `purescript-mode-hook' documentation for examples. + +Currently `purescript-indentation' is the most maintained mode.")) (defun purescript-mode-format-imports () "Format the imports by aligning and sorting them." From c5ed55ac08c785264248807dcdaca4451ab18d52 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Fri, 30 May 2025 01:12:49 +0300 Subject: [PATCH 93/99] README: remove "contributing" and "support" sections These sections have no useful information. "Support" is just a link to the project (which is pointless, because if a user reads this section, they already at the project), and "Contributing" just contains nothing useful. --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index 2b1a524..bc0ef21 100644 --- a/README.md +++ b/README.md @@ -81,13 +81,3 @@ Minimal configuration may look something like: (add-hook 'before-save-hook #'purescript-sort-imports nil t)) (add-hook 'purescript-mode-hook #'myhook-purescript-mode)) ``` - -Support -------- - -- [Github homepage](https://github.com/purescript-emacs/purescript-mode) - -Contributing ------------- - -Please make sure your pull requests are at least properly rebased and up to date. From 6ef23e7586ebc1d3ab3c07c1664adf3190ddf8b5 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Tue, 3 Jun 2025 20:10:14 +0300 Subject: [PATCH 94/99] Test another broken behavior about case-of followed by a list --- tests/purescript-indentation-tests.el | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/purescript-indentation-tests.el b/tests/purescript-indentation-tests.el index 0cc77b0..c3fd10f 100644 --- a/tests/purescript-indentation-tests.el +++ b/tests/purescript-indentation-tests.el @@ -263,3 +263,18 @@ test3 a = case a of { x: y } -> y")) + +(ert-deftest comma-first-list-after-case-of () + "A comma-first list was getting misindented if goes after case-of" + :expected-result :failed + (purescript-test-indentation " +fun = case _ of + [ a + , b ] +" + +" +fun = case _ of + [ a + , b ] +")) From 8dda6cbe17324cf8aed55a21ac0a23fc5a5a0391 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 5 Jun 2025 00:11:35 +0300 Subject: [PATCH 95/99] tests: factor out indentation testing, where before == after --- tests/purescript-indentation-tests.el | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tests/purescript-indentation-tests.el b/tests/purescript-indentation-tests.el index c3fd10f..2a885b7 100644 --- a/tests/purescript-indentation-tests.el +++ b/tests/purescript-indentation-tests.el @@ -21,6 +21,14 @@ (require 'purescript-mode) (require 'purescript-indentation) +(defun purescript-test-indentation-expected-only (expected) + (with-temp-buffer + (insert expected) + (purescript-mode) + (turn-on-purescript-indentation) + (indent-region (point-min) (point-max)) + (should (string= expected (buffer-string))))) + (defun purescript-test-indentation (before after &optional start-line) (with-temp-buffer (insert before) @@ -210,15 +218,11 @@ type MyRec = { data :: Number (ert-deftest func-with-do () :expected-result :failed - (purescript-test-indentation " -foo :: Foo -foo = do - pure unit" - -" + (purescript-test-indentation-expected-only " foo :: Foo foo = do - pure unit")) + pure unit +")) (ert-deftest do-bindings () :expected-result :failed @@ -267,13 +271,7 @@ test3 a (ert-deftest comma-first-list-after-case-of () "A comma-first list was getting misindented if goes after case-of" :expected-result :failed - (purescript-test-indentation " -fun = case _ of - [ a - , b ] -" - -" + (purescript-test-indentation-expected-only " fun = case _ of [ a , b ] From 073e742cfe57615c3498db67ba73d5cb2c8ae77e Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 5 Jun 2025 00:13:33 +0300 Subject: [PATCH 96/99] tests: test multiline function type declarations --- tests/purescript-indentation-tests.el | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/purescript-indentation-tests.el b/tests/purescript-indentation-tests.el index 2a885b7..c058d67 100644 --- a/tests/purescript-indentation-tests.el +++ b/tests/purescript-indentation-tests.el @@ -276,3 +276,20 @@ fun = case _ of [ a , b ] ")) + +(ert-deftest multiline-func-decl-arrow-first () + (purescript-test-indentation-expected-only " +foo :: + ∀ a. A + -> B + -> C +")) + +(ert-deftest multiline-func-decl-arrow-last () + (purescript-test-indentation-expected-only " +foo :: + ∀ a. + A -> + B -> + C +")) From 5a48745abcf2288a32b602f4e3b645f746f8bfbc Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 5 Jun 2025 07:26:18 +0300 Subject: [PATCH 97/99] README.md: replace "purescript mode" chapter with a single sentence The chapter isn't very useful, most people know that git-forges like Github and Gitlab allow reporting issues, and the rest of the text doesn't add much value either. So replace it with a single sentence clarifying what the mode is for. --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index bc0ef21..f31ebed 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,7 @@ [![MELPA](https://melpa.org/packages/purescript-mode-badge.svg)](https://melpa.org/#/purescript-mode) [![Build Status](https://github.com/purescript-emacs/purescript-mode/workflows/CI/badge.svg)](https://github.com/purescript-emacs/purescript-mode/actions) -PureScript Mode for Emacs ----------------------- - -This is the PureScript mode package for Emacs. - -To report problems or suggestions, please -[open an issue](https://github.com/dysinger/purescript-mode/issues?state=open) -in the issue tracker. - -Below is a brief setup guide. +This Emacs package provides indentation, syntax highlighting, and other facilities for PureScript language. Quick Emacs rundown -------------------- From 475620d9b7d73602ab2727798da2426770d37396 Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Thu, 5 Jun 2025 07:32:27 +0300 Subject: [PATCH 98/99] README.md: remove "Quick Emacs rundown" section The mode requires somewhat involved initial setup with configuring indentation-hooks (not to mention even using Melpa requires first adding it to `package-archives'), so as it stands it doesn't really target people who doesn't even know what an init file is. That chapter of README isn't really useful IMO, let's just remove it. --- README.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/README.md b/README.md index f31ebed..4306d71 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,6 @@ This Emacs package provides indentation, syntax highlighting, and other facilities for PureScript language. -Quick Emacs rundown --------------------- - -When Emacs is started up, it normally loads the -[Emacs initialization file](http://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html) -usually called `~/.emacs`, `~/.emacs.el`, or `~/.emacs.d/init.el`; -with `~` standing for for your home directory. This file should -contain all of your personal customisations written as a series of -Emacs Lisp commands. In the following sections, this file will simply -be referred to as the `.emacs` file. - Installation ------------ From 48ab1e7252efd6429cfa1a7d48e2ad2ff119ff1e Mon Sep 17 00:00:00 2001 From: Konstantin Kharlamov Date: Sat, 7 Jun 2025 22:55:30 +0300 Subject: [PATCH 99/99] purescript-indentation: remove unused functions This removes 3 functions from purescript-indentation module that are not used anywhere in the code and are not even documented. Hopefully should simplify digging into the indentation engine further. --- purescript-indentation.el | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/purescript-indentation.el b/purescript-indentation.el index f972bff..1a8bc81 100644 --- a/purescript-indentation.el +++ b/purescript-indentation.el @@ -739,17 +739,6 @@ indent the current line. This has to be fixed elsewhere." (let ((current-indent (purescript-current-column))) (funcall parser))) -(defun purescript-indentation-simple-declaration () - (purescript-indentation-expression) - (cond ((string= current-token "=") - (purescript-indentation-statement-right #'purescript-indentation-expression)) - ((string= current-token "::") - (purescript-indentation-statement-right #'purescript-indentation-type)) - ((and (eq current-token 'end-tokens) - (string= following-token "=")) - (purescript-indentation-add-indentation current-indent) - (throw 'parse-end nil)))) - (defun purescript-indentation-declaration () (purescript-indentation-expression) (cond ((string= current-token "|") @@ -798,21 +787,6 @@ indent the current line. This has to be fixed elsewhere." (unless (member (car parser) '("(" "[" "{" "do" "case")) (throw 'return nil))))))))) -(defun purescript-indentation-test-indentations () - (interactive) - (let ((indentations (save-excursion (purescript-indentation-find-indentations))) - (str "") - (pos 0)) - (while indentations - (when (>= (car indentations) pos) - (setq str (concat str (make-string (- (car indentations) pos) ?\ ) - "|")) - (setq pos (+ 1 (car indentations)))) - (setq indentations (cdr indentations))) - (end-of-line) - (newline) - (insert str))) - (defun purescript-indentation-separated (parser separator stmt-separator) (catch 'return (while t @@ -938,14 +912,6 @@ indent the current line. This has to be fixed elsewhere." (setq possible-indentations (cons indent possible-indentations)))) -(defun purescript-indentation-token-test () - (let ((current-token nil) - (following-token nil) - (layout-indent 0) - (parse-line-number 0) - (indentation-point (mark))) - (purescript-indentation-read-next-token))) - (defun purescript-indentation-read-next-token () (cond ((eq current-token 'end-tokens) 'end-tokens)