diff --git a/haskell-cabal.el b/haskell-cabal.el index 056acdd85..e0f6664de 100644 --- a/haskell-cabal.el +++ b/haskell-cabal.el @@ -1,6 +1,7 @@ ;;; haskell-cabal.el --- Support for Cabal packages -*- lexical-binding: t -*- -;; Copyright (C) 2007, 2008 Stefan Monnier +;; Copyright © 2007, 2008 Stefan Monnier +;; 2016 Arthur Fayzrakhmanov ;; Author: Stefan Monnier @@ -857,7 +858,7 @@ Source names from main-is and c-sources sections are left untouched ) (defun haskell-cabal-find-or-create-source-file () - "Open the source file this line refers to" + "Open the source file this line refers to." (interactive) (let* ((src-dirs (append (haskell-cabal-subsection-entry-list (haskell-cabal-section) "hs-source-dirs") @@ -868,17 +869,25 @@ Source names from main-is and c-sources sections are left untouched (let ((candidates (delq nil (mapcar (lambda (dir) - (let ((file (haskell-cabal-join-paths base-dir dir filename))) + (let ((file (haskell-cabal-join-paths base-dir + dir + filename))) (when (and (file-readable-p file) (not (file-directory-p file))) file))) src-dirs)))) (if (null candidates) - (let* ((src-dir (haskell-cabal-join-paths base-dir (or (car src-dirs) ""))) - (newfile (haskell-cabal-join-paths src-dir filename)) - (do-create-p (y-or-n-p (format "Create file %s ?" newfile)))) - (when do-create-p - (find-file-other-window newfile ))) + (unwind-protect + (progn + (haskell-mode-toggle-interactive-prompt-state) + (let* ((src-dir + (haskell-cabal-join-paths base-dir + (or (car src-dirs) ""))) + (newfile (haskell-cabal-join-paths src-dir filename)) + (do-create-p (y-or-n-p (format "Create file %s ?" newfile)))) + (when do-create-p + (find-file-other-window newfile )))) + (haskell-mode-toggle-interactive-prompt-state t)) (find-file-other-window (car candidates))))))) @@ -986,40 +995,50 @@ Source names from main-is and c-sources sections are left untouched 'haskell-cabal-sort-lines-key-fun))))))) (defun haskell-cabal-add-build-dependency (dependency &optional sort silent) - "Add the given build dependency to every section" + "Add the given DEPENDENCY to every section in cabal file. +If SORT argument is given sort dependencies in section after update. +Pass SILENT argument to update all sections without asking user." (haskell-cabal-map-sections (lambda (section) (when (haskell-cabal-source-section-p section) - (when (or silent - (y-or-n-p (format "Add dependency %s to %s section %s?" - dependency - (haskell-cabal-section-name section) - (haskell-cabal-section-value section)))) - (haskell-cabal-section-add-build-dependency dependency sort section) - nil))))) - -(defun haskell-cabal-add-dependency (package &optional version no-prompt - sort silent) - "Add PACKAGE (and optionally suffix -VERSION) to the cabal -file. Prompts the user before doing so. - + (unwind-protect + (progn + (when + (or silent + (y-or-n-p (format "Add dependency %s to %s section %s?" + dependency + (haskell-cabal-section-name section) + (haskell-cabal-section-value section)))) + (haskell-cabal-section-add-build-dependency dependency + sort + section)) + nil) + (haskell-mode-toggle-interactive-prompt-state t)))))) + +(defun haskell-cabal-add-dependency + (package &optional version no-prompt sort silent) + "Add PACKAGE to the cabal file. If VERSION is non-nil it will be appended as a minimum version. -If NO-PROMPT is nil the minimum-version is read from the minibuffer -When SORT is non-nil the package entries are sorted afterwards -If SILENT ist nil the user is prompted for each source-section -" +If NO-PROMPT is nil the minimum package version is read from the +minibuffer. When SORT is non-nil the package entries are sorted +afterwards. If SILENT is non-nil the user is prompted for each +source-section." (interactive - (list (read-from-minibuffer "Package entry: ") - nil t t nil)) - (save-window-excursion - (find-file-other-window (haskell-cabal-find-file)) - (let ((entry (if no-prompt package - (read-from-minibuffer - "Package entry: " - (concat package (if version (concat " >= " version) "")))))) - (haskell-cabal-add-build-dependency entry sort silent) - (when (or silent (y-or-n-p "Save cabal file?")) - (save-buffer))))) + (list (read-from-minibuffer "Package entry: ") nil t t nil)) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (save-window-excursion + (find-file-other-window (haskell-cabal-find-file)) + (let ((entry (if no-prompt package + (read-from-minibuffer + "Package entry: " + (concat package + (if version (concat " >= " version) "")))))) + (haskell-cabal-add-build-dependency entry sort silent) + (when (or silent (y-or-n-p "Save cabal file?")) + (save-buffer)))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t))) (provide 'haskell-cabal) diff --git a/haskell-commands.el b/haskell-commands.el index 9715d988c..519a77e5f 100644 --- a/haskell-commands.el +++ b/haskell-commands.el @@ -6,7 +6,8 @@ ;;; specific commands such as show type signature, show info, haskell process ;;; commands and etc. -;; Copyright (c) 2014 Chris Done. All rights reserved. +;; Copyright © 2014 Chris Done. All rights reserved. +;; 2016 Arthur Fayzrakhmanov ;; 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 @@ -25,6 +26,7 @@ (require 'cl-lib) (require 'etags) +(require 'haskell-mode) (require 'haskell-compat) (require 'haskell-process) (require 'haskell-font-lock) @@ -740,39 +742,53 @@ inferior GHCi process." (interactive) (let ((session (haskell-interactive-session)) (changed nil)) - (if (null (haskell-session-get session - 'ignored-files)) + (if (null (haskell-session-get session 'ignored-files)) (message "Nothing to unignore!") - (cl-loop for file in (haskell-session-get session - 'ignored-files) - do (cl-case (read-event - (propertize (format "Set permissions? %s (y, n, v: stop and view file)" - file) - 'face 'minibuffer-prompt)) - (?y - (haskell-process-unignore-file session file) - (setq changed t)) - (?v - (find-file file) - (cl-return)))) - (when (and changed - (y-or-n-p "Restart GHCi process now? ")) - (haskell-process-restart))))) + (cl-loop for file in (haskell-session-get session 'ignored-files) + do + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (progn + (cl-case + (read-event + (propertize + (format "Set permissions? %s (y, n, v: stop and view file)" + file) + 'face + 'minibuffer-prompt)) + (?y + (haskell-process-unignore-file session file) + (setq changed t)) + (?v + (find-file file) + (cl-return))) + (when (and changed + (y-or-n-p "Restart GHCi process now? ")) + (haskell-process-restart))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t)))))) ;;;###autoload (defun haskell-session-change-target (target) "Set the build TARGET for cabal REPL." (interactive (list - (completing-read "New build target: " (haskell-cabal-enum-targets) - nil nil nil 'haskell-cabal-targets-history))) + (completing-read "New build target: " + (haskell-cabal-enum-targets) + nil + nil + nil + 'haskell-cabal-targets-history))) (let* ((session haskell-session) (old-target (haskell-session-get session 'target))) (when session (haskell-session-set-target session target) - (when (and (not (string= old-target target)) - (y-or-n-p "Target changed, restart haskell process?")) - (haskell-process-start session))))) + (when (not (string= old-target target)) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p "Target changed, restart haskell process?") + (haskell-process-start session))) + (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload (defun haskell-mode-stylish-buffer () diff --git a/haskell-debug.el b/haskell-debug.el index bdd908c8f..969112076 100644 --- a/haskell-debug.el +++ b/haskell-debug.el @@ -1,6 +1,7 @@ ;;; haskell-debug.el --- Debugging mode via GHCi -*- lexical-binding: t -*- -;; Copyright (c) 2014 Chris Done. All rights reserved. +;; Copyright © 2014 Chris Done. All rights reserved. +;; 2016 Arthur Fayzrakhmanov ;; 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 @@ -223,13 +224,16 @@ (cond ((get-text-property (point) 'break) (let ((break (get-text-property (point) 'break))) - (when (y-or-n-p (format "Delete breakpoint #%d?" - (plist-get break :number))) - (haskell-process-queue-sync-request - (haskell-debug-process) - (format ":delete %d" - (plist-get break :number))) - (haskell-debug/refresh)))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p (format "Delete breakpoint #%d?" + (plist-get break :number))) + (haskell-process-queue-sync-request + (haskell-debug-process) + (format ":delete %d" + (plist-get break :number))) + (haskell-debug/refresh)) + (haskell-mode-toggle-interactive-prompt-state t)))))) (defun haskell-debug/trace () "Trace the expression." @@ -272,16 +276,20 @@ (t (if context (message "Computation finished.") - (when (y-or-n-p "Computation completed without breaking. Reload the module and retry?") - (message "Reloading and resetting breakpoints...") - (haskell-interactive-mode-reset-error (haskell-debug-session)) - (cl-loop for break in breakpoints - do (haskell-process-queue-sync-request - (haskell-debug-process) - (concat ":load " (plist-get break :path)))) - (cl-loop for break in breakpoints - do (haskell-debug-break break)) - (haskell-debug/step expr))))))))) + (progn + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p "Computation completed without breaking. Reload the module and retry?") + (message "Reloading and resetting breakpoints...") + (haskell-interactive-mode-reset-error (haskell-debug-session)) + (cl-loop for break in breakpoints + do (haskell-process-queue-sync-request + (haskell-debug-process) + (concat ":load " (plist-get break :path)))) + (cl-loop for break in breakpoints + do (haskell-debug-break break)) + (haskell-debug/step expr)) + (haskell-mode-toggle-interactive-prompt-state t)))))))))) (haskell-debug/refresh))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/haskell-doc.el b/haskell-doc.el index 861e5119c..3ddd0af13 100644 --- a/haskell-doc.el +++ b/haskell-doc.el @@ -1,7 +1,8 @@ ;;; haskell-doc.el --- show function types in echo area -*- coding: utf-8; lexical-binding: t -*- -;; Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. -;; Copyright (C) 1997 Hans-Wolfgang Loidl +;; Copyright © 2004, 2005, 2006, 2007, 2009, 2016 Free Software Foundation, Inc. +;; Copyright © 1997 Hans-Wolfgang Loidl +;; 2016 Arthur Fayzrakhmanov ;; Author: Hans-Wolfgang Loidl ;; Temporary Maintainer and Hacker: Graeme E Moss @@ -1424,6 +1425,7 @@ is not." This function is run by an idle timer to print the type automatically if `haskell-doc-mode' is turned on." (and haskell-doc-mode + (not haskell-mode-interactive-prompt-state) (not (eobp)) (not executing-kbd-macro) ;; Having this mode operate in the minibuffer makes it impossible to diff --git a/haskell-hoogle.el b/haskell-hoogle.el index e591f4c6b..7f673150a 100644 --- a/haskell-hoogle.el +++ b/haskell-hoogle.el @@ -1,6 +1,7 @@ ;;; haskell-hoogle.el --- Look up Haskell documentation via hoogle or hayoo -*- lexical-binding: t; -*- -;; Copyright (C) 2015 Steve Purcell +;; Copyright © 2015 Steve Purcell +;; 2016 Arthur Fayzrakhmanov ;; Author: Steve Purcell ;; Keywords: docs @@ -113,10 +114,12 @@ is asked to show extra info for the items matching QUERY.." (browse-url (format "http://localhost:%i/?hoogle=%s" haskell-hoogle-port-number (read-string "hoogle: " (haskell-ident-at-point)))) - (when (y-or-n-p "Hoogle server not running, start hoogle server? ") - (haskell-hoogle-start-server)))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p "Hoogle server not running, start hoogle server? ") + (haskell-hoogle-start-server)) + (haskell-mode-toggle-interactive-prompt-state t)))) - (defcustom haskell-hayoo-url "http://hayoo.fh-wedel.de/?query=%s" "Default value for hayoo web site." diff --git a/haskell-interactive-mode.el b/haskell-interactive-mode.el index 24e1fadbb..73c3c0c9b 100644 --- a/haskell-interactive-mode.el +++ b/haskell-interactive-mode.el @@ -1,6 +1,7 @@ ;;; haskell-interactive-mode.el --- The interactive Haskell mode -*- lexical-binding: t -*- -;; Copyright (C) 2011-2012 Chris Done +;; Copyright © 2011-2012 Chris Done +;; 2016 Arthur Fayzrakhmanov ;; Author: Chris Done @@ -27,6 +28,7 @@ ;;; Code: +(require 'haskell-mode) (require 'haskell-compile) (require 'haskell-navigate-imports) (require 'haskell-process) @@ -552,49 +554,61 @@ FILE-NAME only." span)) (defun haskell-process-suggest-add-package (session msg) - "Add the (matched) module to your cabal file." + "Add tthe (matched) module to your cabal file. +Cabal file is selected using SESSION's name, module matching is done in MSG." (let* ((suggested-package (match-string 1 msg)) (package-name (replace-regexp-in-string "-[^-]+$" "" suggested-package)) (version (progn (string-match "\\([^-]+\\)$" suggested-package) (match-string 1 suggested-package))) (cabal-file (concat (haskell-session-name session) ".cabal"))) - (when (y-or-n-p - (format "Add `%s' to %s?" - package-name - cabal-file)) - (haskell-cabal-add-dependency package-name version nil t) - (when (y-or-n-p (format "Enable -package %s in the GHCi session?" package-name)) - (haskell-process-queue-without-filters (haskell-session-process session) - (format ":set -package %s" package-name)))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p + (format "Add `%s' to %s?" + package-name + cabal-file)) + (haskell-cabal-add-dependency package-name version nil t) + (when (y-or-n-p (format "Enable -package %s in the GHCi session?" package-name)) + (haskell-process-queue-without-filters + (haskell-session-process session) + (format ":set -package %s" package-name)))) + (haskell-mode-toggle-interactive-prompt-state t)))) (defun haskell-process-suggest-remove-import (session file import line) - "Suggest removing or commenting out IMPORT on LINE." + "Suggest removing or commenting out import statement. +Asks user to handle redundant import statement using interactive +SESSION in specified FILE to remove IMPORT on given LINE." (let ((first t)) - (cl-case (read-event - (propertize (format "%sThe import line `%s' is redundant. Remove? (y, n, c: comment out) " - (if (not first) - "Please answer n, y or c: " - "") - import) - 'face 'minibuffer-prompt)) - (?y - (haskell-process-find-file session file) - (save-excursion - (goto-char (point-min)) - (forward-line (1- line)) - (goto-char (line-beginning-position)) - (delete-region (line-beginning-position) - (line-end-position)))) - (?n - (message "Ignoring redundant import %s" import)) - (?c - (haskell-process-find-file session file) - (save-excursion - (goto-char (point-min)) - (forward-line (1- line)) - (goto-char (line-beginning-position)) - (insert "-- ")))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (cl-case (read-event + (propertize (format "%sThe import line `%s' is redundant. Remove? (y, n, c: comment out) " + (if (not first) + "Please answer n, y or c: " + "") + import) + 'face + 'minibuffer-prompt)) + (?y + (haskell-process-find-file session file) + (save-excursion + (goto-char (point-min)) + (forward-line (1- line)) + (goto-char (line-beginning-position)) + (delete-region (line-beginning-position) + (line-end-position)))) + (?n + (message "Ignoring redundant import %s" import)) + (?c + (haskell-process-find-file session file) + (save-excursion + (goto-char (point-min)) + (forward-line (1- line)) + (goto-char (line-beginning-position)) + (insert "-- ")))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t)))) (defun haskell-process-find-file (session file) "Find the given file in the project." @@ -605,13 +619,18 @@ FILE-NAME only." (t file)))) (defun haskell-process-suggest-pragma (session pragma extension file) - "Suggest to add something to the top of the file." + "Suggest to add something to the top of the file. +SESSION is used to search given file. Adds PRAGMA and EXTENSION +wrapped in compiler directive at the top of FILE." (let ((string (format "{-# %s %s #-}" pragma extension))) - (when (y-or-n-p (format "Add %s to the top of the file? " string)) - (haskell-process-find-file session file) - (save-excursion - (goto-char (point-min)) - (insert (concat string "\n")))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p (format "Add %s to the top of the file? " string)) + (haskell-process-find-file session file) + (save-excursion + (goto-char (point-min)) + (insert (concat string "\n")))) + (haskell-mode-toggle-interactive-prompt-state t)))) (defun haskell-interactive-mode-insert-error (response) "Insert an error message." diff --git a/haskell-load.el b/haskell-load.el index f9834a3be..92e3f645e 100644 --- a/haskell-load.el +++ b/haskell-load.el @@ -28,8 +28,8 @@ (require 'haskell-session) (defun haskell-process-look-config-changes (session) - "Checks whether a cabal configuration file has -changed. Restarts the process if that is the case." + "Check whether a cabal configuration file has changed. +Restarts the SESSION's process if that is the case." (let ((current-checksum (haskell-session-get session 'cabal-checksum)) (new-checksum (haskell-cabal-compute-checksum (haskell-session-get session 'cabal-dir)))) @@ -40,10 +40,14 @@ changed. Restarts the process if that is the case." (haskell-session-set-cabal-checksum session (haskell-session-get session 'cabal-dir)) - (unless - (and haskell-process-prompt-restart-on-cabal-change - (not (y-or-n-p "Cabal file changed; restart GHCi process? "))) - (haskell-process-start (haskell-interactive-session)))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (unless + (and haskell-process-prompt-restart-on-cabal-change + (not + (y-or-n-p "Cabal file changed. Restart GHCi process? "))) + (haskell-process-start (haskell-interactive-session))) + (haskell-mode-toggle-interactive-prompt-state t))))) (defun haskell-process-live-build (process buffer echo-in-repl) "Show live updates for loading files." @@ -125,34 +129,39 @@ actual Emacs buffer of the module being loaded." (quit nil))))) (defun haskell-process-suggest-imports (session file modules ident) - "Given a list of MODULES, suggest adding them to the import section." + "Suggest add missed imports to file. +Asks user to add to SESSION's FILE missed import. MODULES is a +list of modules where missed IDENT was found." (cl-assert session) (cl-assert file) (cl-assert ident) - (let* ((process (haskell-session-process session)) - (suggested-already (haskell-process-suggested-imports process)) - (module - (cond - ((> (length modules) 1) - (when (y-or-n-p - (format - "Identifier `%s' not in scope, choose module to import?" - ident)) - (haskell-complete-module-read "Module: " modules))) - ((= (length modules) 1) - (let ((module (car modules))) - (unless (member module suggested-already) - (haskell-process-set-suggested-imports - process - (cons module suggested-already)) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (let* ((process (haskell-session-process session)) + (suggested-already (haskell-process-suggested-imports process)) + (module + (cond + ((> (length modules) 1) (when (y-or-n-p - (format "Identifier `%s' not in scope, import `%s'?" - ident - module)) - module))))))) - (when module - (haskell-process-find-file session file) - (haskell-add-import module)))) + (format + "Identifier `%s' not in scope, choose module to import?" + ident)) + (haskell-complete-module-read "Module: " modules))) + ((= (length modules) 1) + (let ((module (car modules))) + (unless (member module suggested-already) + (haskell-process-set-suggested-imports + process + (cons module suggested-already)) + (when (y-or-n-p + (format "Identifier `%s' not in scope, import `%s'?" + ident + module)) + module))))))) + (when module + (haskell-process-find-file session file) + (haskell-add-import module))) + (haskell-mode-toggle-interactive-prompt-state t))) (defun haskell-process-trigger-suggestions (session msg file line) "Trigger prompting to add any extension suggestions." @@ -559,40 +568,43 @@ applications. Put your development version of the program in new thread, and use the `foreign-store' package to access the running context across :load/:reloads in GHCi." (interactive) - (with-current-buffer - (or (get-buffer "DevelMain.hs") - (if (y-or-n-p - "You need to open a buffer named DevelMain.hs. Find now?") - (ido-find-file) - (error "No DevelMain.hs buffer."))) - (let ((session (haskell-interactive-session))) - (let ((process (haskell-interactive-process))) - (haskell-process-queue-command - process - (make-haskell-command - :state (list :session session - :process process - :buffer (current-buffer)) - :go (lambda (state) - (haskell-process-send-string (plist-get state ':process) - ":l DevelMain")) - :live (lambda (state buffer) - (haskell-process-live-build (plist-get state ':process) - buffer - nil)) - :complete (lambda (state response) - (haskell-process-load-complete - (plist-get state ':session) - (plist-get state ':process) - response - nil - (plist-get state ':buffer) - (lambda (ok) - (when ok - (haskell-process-queue-without-filters - (haskell-interactive-process) - "DevelMain.update") - (message "DevelMain updated."))))))))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (with-current-buffer + (or (get-buffer "DevelMain.hs") + (if (y-or-n-p + "You need to open a buffer named DevelMain.hs. Find now?") + (ido-find-file) + (error "No DevelMain.hs buffer."))) + (let ((session (haskell-interactive-session))) + (let ((process (haskell-interactive-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (list :session session + :process process + :buffer (current-buffer)) + :go (lambda (state) + (haskell-process-send-string (plist-get state ':process) + ":l DevelMain")) + :live (lambda (state buffer) + (haskell-process-live-build (plist-get state ':process) + buffer + nil)) + :complete (lambda (state response) + (haskell-process-load-complete + (plist-get state ':session) + (plist-get state ':process) + response + nil + (plist-get state ':buffer) + (lambda (ok) + (when ok + (haskell-process-queue-without-filters + (haskell-interactive-process) + "DevelMain.update") + (message "DevelMain updated.")))))))))) + (haskell-mode-toggle-interactive-prompt-state t))) (provide 'haskell-load) ;;; haskell-load.el ends here diff --git a/haskell-mode.el b/haskell-mode.el index f5fc04714..d45384e32 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -1,13 +1,16 @@ ;;; haskell-mode.el --- A Haskell 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 +;; Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2016 +;; Free Software Foundation, Inc + +;; Copyright © 1992, 1997-1998 Simon Marlow, Graeme E Moss, and Tommy Thorn ;; Author: 1992 Simon Marlow ;; 1997-1998 Graeme E Moss and ;; Tommy Thorn , ;; 2001-2002 Reuben Thomas (>=v1.4) ;; 2003 Dave Love +;; 2016 Arthur Fayzrakhmanov ;; Keywords: faces files Haskell ;; Version: 16.1-git ;; URL: https://github.com/haskell/haskell-mode @@ -570,6 +573,10 @@ May return a qualified name." (defvar eldoc-print-current-symbol-info-function) +(defvar haskell-mode-interactive-prompt-state nil + "Special variable indicating a state of user input waiting.") + + ;; For compatibility with Emacs < 24, derive conditionally (defalias 'haskell-parent-mode (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode)) @@ -956,7 +963,12 @@ successful, nil otherwise." (goto-char (point-min)) (end-of-line))) - +(defun haskell-mode-toggle-interactive-prompt-state (&optional disabled) + "Set `haskell-mode-interactive-prompt-state' to t. +If given DISABLED argument sets variable value to nil, otherwise to t." + (setq haskell-mode-interactive-prompt-state (not disabled))) + + ;; Provide ourselves: (provide 'haskell-mode) diff --git a/haskell.el b/haskell.el index cbf5c816f..8995d97a1 100644 --- a/haskell.el +++ b/haskell.el @@ -1,6 +1,7 @@ ;;; haskell.el --- Top-level Haskell package -*- lexical-binding: t -*- -;; Copyright (c) 2014 Chris Done. All rights reserved. +;; Copyright © 2014 Chris Done. All rights reserved. +;; 2016 Arthur Fayzrakhmanov ;; 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 @@ -15,6 +16,8 @@ ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . +;;; Commentary: + ;;; Code: (require 'cl-lib) @@ -132,40 +135,49 @@ "Kill the session process and buffer, delete the session. 0. Prompt to kill all associated buffers. 1. Kill the process. -2. Kill the interactive buffer. +2. Kill the interactive buffer unless LEAVE-INTERACTIVE-BUFFER is not given. 3. Walk through all the related buffers and set their haskell-session to nil. 4. Remove the session from the sessions list." (interactive) - (let* ((session (haskell-session)) - (name (haskell-session-name session)) - (also-kill-buffers - (and haskell-ask-also-kill-buffers - (y-or-n-p (format "Killing `%s'. Also kill all associated buffers?" name))))) - (haskell-kill-session-process session) - (unless leave-interactive-buffer - (kill-buffer (haskell-session-interactive-buffer session))) - (cl-loop for buffer in (buffer-list) - do (with-current-buffer buffer - (when (and (boundp 'haskell-session) - (string= (haskell-session-name haskell-session) name)) - (setq haskell-session nil) - (when also-kill-buffers - (kill-buffer))))) - (setq haskell-sessions - (cl-remove-if (lambda (session) - (string= (haskell-session-name session) - name)) - haskell-sessions)))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (let* ((session (haskell-session)) + (name (haskell-session-name session)) + (also-kill-buffers + (and haskell-ask-also-kill-buffers + (y-or-n-p + (format "Killing `%s'. Also kill all associated buffers?" + name))))) + (haskell-kill-session-process session) + (unless leave-interactive-buffer + (kill-buffer (haskell-session-interactive-buffer session))) + (cl-loop for buffer in (buffer-list) + do (with-current-buffer buffer + (when (and (boundp 'haskell-session) + (string= (haskell-session-name haskell-session) + name)) + (setq haskell-session nil) + (when also-kill-buffers + (kill-buffer))))) + (setq haskell-sessions + (cl-remove-if (lambda (session) + (string= (haskell-session-name session) + name)) + haskell-sessions))) + (haskell-mode-toggle-interactive-prompt-state t))) ;;;###autoload (defun haskell-interactive-kill () "Kill the buffer and (maybe) the session." (interactive) (when (eq major-mode 'haskell-interactive-mode) - (when (and (boundp 'haskell-session) - haskell-session - (y-or-n-p "Kill the whole session?")) - (haskell-session-kill t)))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (and (boundp 'haskell-session) + haskell-session + (y-or-n-p "Kill the whole session?")) + (haskell-session-kill t))) + (haskell-mode-toggle-interactive-prompt-state t))) (defun haskell-session-make (name) "Make a Haskell session." @@ -182,9 +194,12 @@ If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (let ((name (haskell-session-default-name))) (unless (haskell-session-lookup name) - (if (or (not haskell-process-load-or-reload-prompt) - (y-or-n-p (format "Start a new project named “%s”? " name))) - (haskell-session-make name))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (if (or (not haskell-process-load-or-reload-prompt) + (y-or-n-p (format "Start a new project named “%s”? " name))) + (haskell-session-make name)) + (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload (defun haskell-session () @@ -212,10 +227,15 @@ If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (let ((name (read-from-minibuffer "Project name: " (haskell-session-default-name)))) (when (not (string= name "")) (let ((session (haskell-session-lookup name))) - (if session - (when (y-or-n-p (format "Session %s already exists. Use it?" name)) - session) - (haskell-session-make name)))))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (if session + (when + (y-or-n-p + (format "Session %s already exists. Use it?" name)) + session) + (haskell-session-make name))) + (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload (defun haskell-session-change () @@ -226,44 +246,60 @@ If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (haskell-session-new)))) (defun haskell-process-prompt-restart (process) - "Prompt to restart the died process." + "Prompt to restart the died PROCESS." (let ((process-name (haskell-process-name process))) (if haskell-process-suggest-restart - (cond - ((string-match "You need to re-run the 'configure' command." - (haskell-process-response process)) - (cl-case (read-event - (concat "The Haskell process ended. Cabal wants you to run " - (propertize "cabal configure" 'face 'font-lock-keyword-face) - " because there is a version mismatch. Re-configure (y, n, l: view log)?" - "\n\n" - "Cabal said:\n\n" - (propertize (haskell-process-response process) - 'face 'font-lock-comment-face))) - (?y (let ((default-directory (haskell-session-cabal-dir (haskell-process-session process)))) - (message "%s" (shell-command-to-string "cabal configure")))) - (?l (let* ((response (haskell-process-response process)) - (buffer (get-buffer "*haskell-process-log*"))) - (if buffer - (switch-to-buffer buffer) - (progn (switch-to-buffer (get-buffer-create "*haskell-process-log*")) - (insert response))))) - (?n))) - (t - (cl-case (read-event - (propertize (format "The Haskell process `%s' has died. Restart? (y, n, l: show process log)" - process-name) - 'face 'minibuffer-prompt)) - (?y (haskell-process-start (haskell-process-session process))) - (?l (let* ((response (haskell-process-response process)) - (buffer (get-buffer "*haskell-process-log*"))) - (if buffer - (switch-to-buffer buffer) - (progn (switch-to-buffer (get-buffer-create "*haskell-process-log*")) - (insert response))))) - (?n)))) - (message (format "The Haskell process `%s' is dearly departed." - process-name))))) + (progn + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (cond + ((string-match "You need to re-run the 'configure' command." + (haskell-process-response process)) + (cl-case (read-event + (concat + "The Haskell process ended. Cabal wants you to run " + (propertize "cabal configure" + 'face + 'font-lock-keyword-face) + " because there is a version mismatch. Re-configure (y, n, l: view log)?" + "\n\n" + "Cabal said:\n\n" + (propertize (haskell-process-response process) + 'face + 'font-lock-comment-face))) + (?y (let ((default-directory + (haskell-session-cabal-dir + (haskell-process-session process)))) + (message "%s" + (shell-command-to-string "cabal configure")))) + (?l (let* ((response (haskell-process-response process)) + (buffer (get-buffer "*haskell-process-log*"))) + (if buffer + (switch-to-buffer buffer) + (progn (switch-to-buffer + (get-buffer-create "*haskell-process-log*")) + (insert response))))) + (?n))) + (t + (cl-case (read-event + (propertize + (format "The Haskell process `%s' has died. Restart? (y, n, l: show process log)" + process-name) + 'face + 'minibuffer-prompt)) + (?y (haskell-process-start (haskell-process-session process))) + (?l (let* ((response (haskell-process-response process)) + (buffer (get-buffer "*haskell-process-log*"))) + (if buffer + (switch-to-buffer buffer) + (progn (switch-to-buffer + (get-buffer-create "*haskell-process-log*")) + (insert response))))) + (?n)))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t))) + (message + (format "The Haskell process `%s' is dearly departed." process-name))))) (defun haskell-process () "Get the current process from the current session." @@ -520,3 +556,4 @@ for various things, but is optional." t)))))) (provide 'haskell) +;;; haskell.el ends here diff --git a/tests/haskell-doc-tests.el b/tests/haskell-doc-tests.el new file mode 100644 index 000000000..ee159cea3 --- /dev/null +++ b/tests/haskell-doc-tests.el @@ -0,0 +1,55 @@ +;;; haskell-doc-tests.el --- Tests for `haskell-docs' package + +;; Copyright © 2016 Arthur Fayzrakhmanov. All rights reserved. + +;; This file is part of haskell-mode package. +;; You can contact with authors using GitHub issue tracker: +;; https://github.com/haskell/haskell-mode/issues + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; This package provides regression tests for haskell-docs package. + +;;; Code: + +(require 'ert) +(require 'haskell-mode) +(require 'haskell-doc) +(require 'haskell-test-utils) + + +(ert-deftest interactive-prompt-state () + (with-temp-buffer + (haskell-mode) + (haskell-doc-mode) + (insert-lines "module A where" + "import B") + (goto-char (point-min)) + (forward-line) + (should (string= + "import [qualified] modid [as modid] [impspec]" + (haskell-doc-mode-print-current-symbol-info))) + (haskell-mode-toggle-interactive-prompt-state) + (should (eq nil + (haskell-doc-mode-print-current-symbol-info))) + (haskell-mode-toggle-interactive-prompt-state t) + (should (string= + "import [qualified] modid [as modid] [impspec]" + (haskell-doc-mode-print-current-symbol-info))))) + +;;; haskell-doc-tests.el ends here