From 54f93cd9cafeeb539745cee24ea86f2cba32ce98 Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Tue, 10 Nov 2015 21:13:04 -0500 Subject: [PATCH 1/8] add haskell-mode-toggle-scc-at-point --- haskell-mode.el | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/haskell-mode.el b/haskell-mode.el index 6ce955509..6a75540f8 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -891,9 +891,9 @@ LOC = (list FILE LINE COL)" ;; From Bryan O'Sullivan's blog: ;; http://www.serpentine.com/blog/2007/10/09/using-emacs-to-insert-scc-annotations-in-haskell-code/ -(defun haskell-mode-insert-scc-at-point () - "Insert an SCC annotation at point." - (interactive) +(defun haskell-mode-try-insert-scc-at-point () + "Try to insert an SCC annotation at point. Return true if +successful, nil otherwise." (if (or (looking-at "\\b\\|[ \t]\\|$") (and (not (bolp)) (save-excursion (forward-char -1) @@ -906,13 +906,18 @@ LOC = (list FILE LINE COL)" (insert "{-# SCC \"\" #-}") (unless space-at-point (insert " ")) - (forward-char (if space-at-point -5 -6))) - (error "Not over an area of whitespace"))) + (forward-char (if space-at-point -5 -6)) + t ))) -;; Also Bryan O'Sullivan's. -(defun haskell-mode-kill-scc-at-point () - "Kill the SCC annotation at point." +(defun haskell-mode-insert-scc-at-point () + "Insert an SCC annotation at point." (interactive) + (if (not (haskell-mode-try-insert-scc-at-point)) + (error "Not over an area of whitespace"))) + +(defun haskell-mode-try-kill-scc-at-point () + "Try to kill an SCC annotation at point. Return true if +successful, nil otherwise." (save-excursion (let ((old-point (point)) (scc "\\({-#[ \t]*SCC \"[^\"]*\"[ \t]*#-}\\)[ \t]*")) @@ -921,8 +926,22 @@ LOC = (list FILE LINE COL)" (if (and (looking-at scc) (<= (match-beginning 1) old-point) (> (match-end 1) old-point)) - (kill-region (match-beginning 0) (match-end 0)) - (error "No SCC at point"))))) + (progn (kill-region (match-beginning 0) (match-end 0)) + t))))) + +;; Also Bryan O'Sullivan's. +(defun haskell-mode-kill-scc-at-point () + "Kill the SCC annotation at point." + (interactive) + (if (not (haskell-mode-try-kill-scc-at-point)) + (error "No SCC at point"))) + +(defun haskell-mode-toggle-scc-at-point () + "If point is in an SCC annotation, kill the annotation. Otherwise, try to insert a new annotation." + (interactive) + (if (not (haskell-mode-try-kill-scc-at-point)) + (if (not (haskell-mode-try-insert-scc-at-point)) + (error "Could not insert or remove SCC")))) (defun haskell-guess-module-name () "Guess the current module name of the buffer." From ea332606d9a5c514fdf9371532f4b3d589f746d2 Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Tue, 10 Nov 2015 21:51:27 -0500 Subject: [PATCH 2/8] bind haskell-mode-toggle-scc-at-point to C-c C-s --- haskell-mode.el | 1 + 1 file changed, 1 insertion(+) diff --git a/haskell-mode.el b/haskell-mode.el index 6a75540f8..1d7e385c0 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -202,6 +202,7 @@ be set to the preferred literate style." (define-key map (kbd "C-c C-v") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-t") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-i") 'haskell-mode-enable-process-minor-mode) + (define-key map (kbd "C-c C-s") 'haskell-mode-toggle-scc-at-point) map) "Keymap used in Haskell mode.") From 0deae63b2f6ead9e2298aa47be6096384e2cc475 Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Tue, 10 Nov 2015 21:55:13 -0500 Subject: [PATCH 3/8] Document `toggle-scc-at-point` in manual --- doc/haskell-mode.texi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/haskell-mode.texi b/doc/haskell-mode.texi index 7d932e767..99108071f 100644 --- a/doc/haskell-mode.texi +++ b/doc/haskell-mode.texi @@ -278,6 +278,15 @@ and available packages. @image{anim/company-mode-import-statement} @end ifhtml +@section Profiling and Debugging support + +When profiling code with GHC, it is often useful to add +@uref{https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html#cost-centres, +cost centres} by hand. These allow finer-grained information about +program behavior. @code{haskell-mode} provides the function +@code{haskell-mode-toggle-scc-at-point} to make this more convenient. +It will remove an SCC annotation at point if one is present, or add +one if point is over whitespace. By default it is bound to @kbd{C-c C-s}. @node Unicode support @chapter Unicode support From b82c5dcdb9631ff81ea9b8d267d7d26a0c6e0bad Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Tue, 10 Nov 2015 22:25:00 -0500 Subject: [PATCH 4/8] add unit tests for toggle-scc-at-point --- tests/haskell-mode-tests.el | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/haskell-mode-tests.el b/tests/haskell-mode-tests.el index 078c246e7..7a0a88c15 100644 --- a/tests/haskell-mode-tests.el +++ b/tests/haskell-mode-tests.el @@ -170,7 +170,7 @@ (should (with-temp-buffer (haskell-mode) (insert "Äöèąċōïá") - (string= "Äöèąċōïá" (haskell-ident-at-point))))) + (string= "Äöèąċōïá" (haskell-ident-at-point))))) (ert-deftest unicode-pos () (should (with-temp-buffer @@ -385,4 +385,31 @@ Also should respect 10 column fill." '("-- @| a b c d" "-- e"))) +(ert-deftest insert-scc-feasible () + "insert an SCC where it's possible to do so" + (should (with-temp-buffer + (insert "hello world") + (goto-char 6) + (haskell-mode-toggle-scc-at-point) + (string= "hello {-# SCC \"\" #-} world" + (buffer-substring 1 (point-max)))))) + +(ert-deftest insert-scc-infeasible () + "insert an SCC where it's not possible to do so" + (should-error (with-temp-buffer + (insert "hello world") + (goto-char 3) + (haskell-mode-toggle-scc-at-point) + (string= "hello world" + (buffer-substring 1 (point-max)))))) + +(ert-deftest remove-scc () + "insert an SCC where it's possible to do so" + (should (with-temp-buffer + (insert "hello {-# SCC \"\" #-} world") + (goto-char 10) + (haskell-mode-toggle-scc-at-point) + (string= "hello world" + (buffer-substring 1 (point-max)))))) + (provide 'haskell-mode-tests) From f1b104b6200f05daec06f452c9ac128797b06777 Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Tue, 10 Nov 2015 23:06:52 -0500 Subject: [PATCH 5/8] modify tests to expose bug in SCC code If point is on the second character of a word, haskell-mode-try-scc-at-point will break the word, inserting an SCC annotation between the first and second characters. --- tests/haskell-mode-tests.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/haskell-mode-tests.el b/tests/haskell-mode-tests.el index 7a0a88c15..6dba27b2b 100644 --- a/tests/haskell-mode-tests.el +++ b/tests/haskell-mode-tests.el @@ -398,7 +398,7 @@ Also should respect 10 column fill." "insert an SCC where it's not possible to do so" (should-error (with-temp-buffer (insert "hello world") - (goto-char 3) + (goto-char 2) (haskell-mode-toggle-scc-at-point) (string= "hello world" (buffer-substring 1 (point-max)))))) From 5c96cd13d6ad728dfcd33265ecd114552ed850ad Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Tue, 10 Nov 2015 23:08:35 -0500 Subject: [PATCH 6/8] fix second-char bug in SCC code Don't insert SCC if the character before point is the beginning of a word. Do insert SCC if the character at point is not the beginning of a word, but the character before point is whitespace. This occurs when the character at point is a non-letter, such as = or {. --- haskell-mode.el | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/haskell-mode.el b/haskell-mode.el index 1d7e385c0..5119b6883 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -895,10 +895,12 @@ LOC = (list FILE LINE COL)" (defun haskell-mode-try-insert-scc-at-point () "Try to insert an SCC annotation at point. Return true if successful, nil otherwise." - (if (or (looking-at "\\b\\|[ \t]\\|$") (and (not (bolp)) - (save-excursion - (forward-char -1) - (looking-at "\\b\\|[ \t]")))) + (if (or (looking-at "\\b\\|[ \t]\\|$") + ;; Allow SCC if point is on a non-letter with whitespace to the left + (and (not (bolp)) + (save-excursion + (forward-char -1) + (looking-at "[ \t]")))) (let ((space-at-point (looking-at "[ \t]"))) (unless (and (not (bolp)) (save-excursion (forward-char -1) From 5ce8ad47774ecc534616b6e889131a72e4655f6c Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Wed, 11 Nov 2015 07:35:08 -0500 Subject: [PATCH 7/8] mark old SCC functions as obsolete --- haskell-mode.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/haskell-mode.el b/haskell-mode.el index 5119b6883..51c961fd6 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -918,6 +918,10 @@ successful, nil otherwise." (if (not (haskell-mode-try-insert-scc-at-point)) (error "Not over an area of whitespace"))) +(make-obsolete + 'haskell-mode-insert-scc-at-point + 'haskell-mode-toggle-scc-at-point) + (defun haskell-mode-try-kill-scc-at-point () "Try to kill an SCC annotation at point. Return true if successful, nil otherwise." @@ -939,6 +943,10 @@ successful, nil otherwise." (if (not (haskell-mode-try-kill-scc-at-point)) (error "No SCC at point"))) +(make-obsolete + 'haskell-mode-kill-scc-at-point + 'haskell-mode-toggle-scc-at-point) + (defun haskell-mode-toggle-scc-at-point () "If point is in an SCC annotation, kill the annotation. Otherwise, try to insert a new annotation." (interactive) From d8d61af1dc230a530cf401d7c6717974940bf973 Mon Sep 17 00:00:00 2001 From: Daniel Bergey Date: Wed, 11 Nov 2015 08:08:00 -0500 Subject: [PATCH 8/8] In make-obsolete, give date of obsolescence --- haskell-mode.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/haskell-mode.el b/haskell-mode.el index 51c961fd6..f22cea8e3 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -920,7 +920,8 @@ successful, nil otherwise." (make-obsolete 'haskell-mode-insert-scc-at-point - 'haskell-mode-toggle-scc-at-point) + 'haskell-mode-toggle-scc-at-point + "2015-11-11") (defun haskell-mode-try-kill-scc-at-point () "Try to kill an SCC annotation at point. Return true if @@ -945,7 +946,8 @@ successful, nil otherwise." (make-obsolete 'haskell-mode-kill-scc-at-point - 'haskell-mode-toggle-scc-at-point) + 'haskell-mode-toggle-scc-at-point + "2015-11-11") (defun haskell-mode-toggle-scc-at-point () "If point is in an SCC annotation, kill the annotation. Otherwise, try to insert a new annotation."