From a01aba3865579411747de1eb62457e193e444e29 Mon Sep 17 00:00:00 2001 From: ncaq Date: Fri, 8 May 2015 19:44:54 +0900 Subject: [PATCH] added: flycheck-haskell --- .../flycheck-haskell-autoloads.el | 34 +++ .../flycheck-haskell-pkg.el | 10 + .../flycheck-haskell.el | 221 ++++++++++++++++++ .../flycheck-haskell.elc | Bin 0 -> 6222 bytes .../get-cabal-configuration.hs | 128 ++++++++++ profile/30_haskell.el | 2 + profile/30_haskell.elc | Bin 1161 -> 1296 bytes 7 files changed, 395 insertions(+) create mode 100644 elpa/flycheck-haskell-20150406.327/flycheck-haskell-autoloads.el create mode 100644 elpa/flycheck-haskell-20150406.327/flycheck-haskell-pkg.el create mode 100644 elpa/flycheck-haskell-20150406.327/flycheck-haskell.el create mode 100644 elpa/flycheck-haskell-20150406.327/flycheck-haskell.elc create mode 100644 elpa/flycheck-haskell-20150406.327/get-cabal-configuration.hs diff --git a/elpa/flycheck-haskell-20150406.327/flycheck-haskell-autoloads.el b/elpa/flycheck-haskell-20150406.327/flycheck-haskell-autoloads.el new file mode 100644 index 000000000..288f56239 --- /dev/null +++ b/elpa/flycheck-haskell-20150406.327/flycheck-haskell-autoloads.el @@ -0,0 +1,34 @@ +;;; flycheck-haskell-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "flycheck-haskell" "flycheck-haskell.el" (21836 +;;;;;; 37615 467297 803000)) +;;; Generated autoloads from flycheck-haskell.el + +(autoload 'flycheck-haskell-setup "flycheck-haskell" "\ +Setup Haskell support for Flycheck. + +If the current file is part of a Cabal project, configure +Flycheck to take the module paths of the Cabal projects into +account. + +Also search for Cabal sandboxes and add them to the module search +path as well. + +\(fn)" nil nil) + +;;;*** + +;;;### (autoloads nil nil ("flycheck-haskell-pkg.el") (21836 37615 +;;;;;; 481651 694000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; flycheck-haskell-autoloads.el ends here diff --git a/elpa/flycheck-haskell-20150406.327/flycheck-haskell-pkg.el b/elpa/flycheck-haskell-20150406.327/flycheck-haskell-pkg.el new file mode 100644 index 000000000..265e9c90d --- /dev/null +++ b/elpa/flycheck-haskell-20150406.327/flycheck-haskell-pkg.el @@ -0,0 +1,10 @@ +(define-package "flycheck-haskell" "20150406.327" "Flycheck: Cabal projects and sandboxes" + '((flycheck "0.22") + (haskell-mode "13.7") + (dash "2.4.0") + (let-alist "1.0.1")) + :url "https://github.com/flycheck/flycheck-haskell" :keywords + '("tools" "convenience")) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/flycheck-haskell-20150406.327/flycheck-haskell.el b/elpa/flycheck-haskell-20150406.327/flycheck-haskell.el new file mode 100644 index 000000000..9f8def953 --- /dev/null +++ b/elpa/flycheck-haskell-20150406.327/flycheck-haskell.el @@ -0,0 +1,221 @@ +;;; flycheck-haskell.el --- Flycheck: Cabal projects and sandboxes -*- lexical-binding: t; -*- + +;; Copyright (C) 2014, 2015 Sebastian Wiesner +;; Copyright (C) 2014 Gracjan Polak + +;; Author: Sebastian Wiesner +;; URL: https://github.com/flycheck/flycheck-haskell +;; Keywords: tools, convenience +;; Version: 0.7-cvs +;; Package-Requires: ((flycheck "0.22") (haskell-mode "13.7") (dash "2.4.0") (let-alist "1.0.1")) + +;; 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: + +;; Configure Haskell syntax checking by Flycheck. + +;;;; Cabal support + +;; Try to find Cabal project files for Haskell buffers, and configure the +;; Haskell syntax checkers in Flycheck according to the contents of the Cabal +;; file: +;; +;; - Add all source directories to the GHC search path +;; - Add build directories from Cabal to the GHC search path to speed up +;; checking and support non-Haskell modules such as hsc files +;; - Add auto-generated files from Cabal to the GHC search path +;; - Set the language from Cabal +;; - Enable language extensions from Cabal + +;;;; Cabal sandboxes + +;; Try to find a Cabal sandbox configuration for this project, and configure the +;; Haskell syntax checkers in Flycheck to use the package database from the +;; Sandbox. + +;;;; Setup + +;; (add-hook 'flycheck-mode-hook #'flycheck-haskell-setup) + +;;; Code: + +(eval-when-compile + (require 'rx) + (require 'let-alist)) + +(require 'haskell-cabal) +(require 'flycheck) +(require 'dash) + + +;;; Customization + +(defgroup flycheck-haskell nil + "Haskell support for Flycheck." + :prefix "flycheck-haskell-" + :group 'flycheck + :link '(url-link :tag "Github" "https://github.com/flycheck/flycheck-haskell")) + +(defcustom flycheck-haskell-runhaskell "runhaskell" + "Path to the `runhaskell' executable. + +This library uses `runhaskell' to run various Haskell helper +scripts to extract information from Cabal files." + :type `(file :must-match t) + :group 'flycheck-haskell) + + +;;; Cabal support +(defconst flycheck-haskell-helper + (expand-file-name "get-cabal-configuration.hs" + (file-name-directory (if load-in-progress + load-file-name + (buffer-file-name)))) + "The helper to dump the Cabal configuration.") + +(defconst flycheck-haskell-config-cache (make-hash-table :test 'equal) + "Cache of Cabal configuration. + +A hash table, mapping the name of a cabal file to a +cons-cell `(MODTIME . CONFIG)', where MODTIME is the modification +time of the cabal file, and CONFIG the extracted configuration.") + +(defun flycheck-haskell-clear-config-cache () + "Clear the cache of configurations." + (interactive) + (clrhash flycheck-haskell-config-cache)) + +(defun flycheck-haskell-get-cached-configuration (cabal-file) + "Get the cached configuration for CABAL-FILE. + +Return the cached configuration, or nil, if there is no cache +entry, or if the cache entry is outdated." + (pcase-let* ((cache-entry (gethash cabal-file flycheck-haskell-config-cache)) + (`(,modtime . ,config) cache-entry)) + (when (and modtime (file-exists-p cabal-file)) + (let ((current-modtime (nth 5 (file-attributes cabal-file)))) + (if (time-less-p modtime current-modtime) + ;; The entry is outdated, drop it. `remhash' always + ;; returns nil, so we are safe to use it here. + (remhash cabal-file flycheck-haskell-config-cache) + ;; The configuration is up to date, use it + config))))) + +(defun flycheck-haskell-read-cabal-configuration (cabal-file) + "Read the Cabal configuration from CABAL-FILE." + (with-temp-buffer + (let ((result (call-process flycheck-haskell-runhaskell nil t nil + flycheck-haskell-helper cabal-file))) + (when (= result 0) + (goto-char (point-min)) + (read (current-buffer)))))) + +(defun flycheck-haskell-read-and-cache-configuration (cabal-file) + "Read and cache configuration from CABAL-FILE. + +Return the configuration." + (let ((modtime (nth 5 (file-attributes cabal-file))) + (config (flycheck-haskell-read-cabal-configuration cabal-file))) + (puthash cabal-file (cons modtime config) flycheck-haskell-config-cache) + config)) + +(defun flycheck-haskell-get-configuration (cabal-file) + "Get the Cabal configuration from CABAL-FILE. + +Get the configuration either from our cache, or by reading the +CABAL-FILE. + +Return the configuration." + (or (flycheck-haskell-get-cached-configuration cabal-file) + (flycheck-haskell-read-and-cache-configuration cabal-file))) + +(defconst flycheck-haskell-sandbox-config "cabal.sandbox.config" + "The file name of a Cabal sandbox configuration.") + +(defconst flycheck-haskell-package-db-re + (rx line-start (zero-or-more (any space)) "package-db:" + (zero-or-more (any space)) + (group (one-or-more (not (any space)))) + (zero-or-more (any space) line-end)) + "Regular expression to parse the package db directory.") + +(defun flycheck-haskell-get-package-db (sandbox-config-file) + "Get the package database directory from SANDBOX-CONFIG-FILE. + +Return the package database directory as string, or nil, if the +database was not found." + (with-temp-buffer + (insert-file-contents sandbox-config-file) + (goto-char (point-min)) + (when (re-search-forward flycheck-haskell-package-db-re nil 'noerror) + (match-string 1)))) + +(defun flycheck-haskell-find-sandbox-config () + "Find Cabal sandbox configuration for the current buffer. + +Return the absolute path of the sandbox configuration file as +string, or nil, if no sandbox configuration file was found." + (-when-let (root-dir (locate-dominating-file (buffer-file-name) + flycheck-haskell-sandbox-config)) + (expand-file-name flycheck-haskell-sandbox-config root-dir))) + +(defun flycheck-haskell-process-configuration (config) + "Process the a Cabal CONFIG." + (let-alist config + (setq-local flycheck-ghc-search-path + (append .build-directories .source-directories + flycheck-ghc-search-path)) + (setq-local flycheck-ghc-language-extensions + (append .extensions .languages + flycheck-ghc-language-extensions)) + (setq-local flycheck-ghc-args + (append .other-options flycheck-ghc-args)))) + +(defun flycheck-haskell-configure () + "Set paths and package database for the current project." + (interactive) + (when (and (buffer-file-name) (file-directory-p default-directory)) + (-when-let* ((cabal-file (haskell-cabal-find-file)) + (config (flycheck-haskell-get-configuration cabal-file))) + (flycheck-haskell-process-configuration config)) + + (-when-let* ((config (flycheck-haskell-find-sandbox-config)) + (package-db (flycheck-haskell-get-package-db config))) + (setq-local flycheck-ghc-package-databases + (cons package-db flycheck-ghc-package-databases)) + (setq-local flycheck-ghc-no-user-package-database t)))) + +;;;###autoload +(defun flycheck-haskell-setup () + "Setup Haskell support for Flycheck. + +If the current file is part of a Cabal project, configure +Flycheck to take the module paths of the Cabal projects into +account. + +Also search for Cabal sandboxes and add them to the module search +path as well." + (add-hook 'hack-local-variables-hook #'flycheck-haskell-configure)) + +(provide 'flycheck-haskell) + +;; Local Variables: +;; indent-tabs-mode: nil +;; coding: utf-8 +;; End: + +;;; flycheck-haskell.el ends here diff --git a/elpa/flycheck-haskell-20150406.327/flycheck-haskell.elc b/elpa/flycheck-haskell-20150406.327/flycheck-haskell.elc new file mode 100644 index 0000000000000000000000000000000000000000..8fc50994ba37c2cdb32de84500d549a176c95a10 GIT binary patch literal 6222 zcmd5=ZExGi5w_#Taa0s&`=wv*&<%Y}temNcq$t@=(VpYHoPpfsa7lpzmJhcgR}yQA zQVcYJf7ioSj|H%QMgH^H* znaiNWCii)HnS`Q9MIaL~QX)>}(jw+#3ZY~kM=BTP6oRg&*M$*&)gNu(*Z#Fyt-aAz zsq7#Pm9U0hw~NbpG;|%hq03!-@al&i-uSrsxCTRyq#XyBOEd7_!_|BIQ0s9Z=|Iwf zqzg&cdHE8*kaHpDLKn~TA3qqn-GL>}a`j6U}W zR7IK2>`(=<%#}UK(<*C3Y%^0NQ7o))wHi@WS(fId7^k^-ZIpE^ag^n19DNd2y+A$N z#yhR|D2|c~u~+4>&38wooCxa;BC{Gsnx!|^^Y=- zwojNWxzwW z7w;4EB!G((i|`W$l`XQD9U$ez&wJm!d->t?yH{BCAmd0D;>k+r1f<0{((I(pL}v%+$oRE7 ziyd#|gE*&cp9{D4YQOKc398P?wNC#)yiw(Rr`K%6@O5(h;`puo`t1?QxR_%5(I0;67dXu&1Mdn5zo~T3t zw}GJQ($?@NEb+8dv+OA_(v&_<_&HnA? zzl#X8LJv?LT1|;W^y3Y{Js@l+`cT5%GCUWD#?`KS(ABO!bhN7p+cc&u0m>RzFJ|ge zEnw*RFQb6U3@>|ge!&{0=^gW7O| zfujxQ^!p9O-7QBNKwPw%P~cmj)l4VSD%Vb6C>vd|*G$E0%|YuLTrR5np8#%A!9osp zHz_9j9Fq>;6R%w{-i;W!BFSdH!QQnqC_|n z4FS4+CuW8nj%*Y%>!-7`qXJ{<==}WY{N2&w@Nl?y_S0PK>*27Cp}#N6e1$PUjb>S% zk3i*8JQy@_+U!( zt9A4D=*Chp-x~S$|EVfONulymb81i@tTaw5y%;(vlj1#Z;2NNG#Sf<1lhveghEC(UB0Kl6YED+s$zZI#!i{csWk(v_ao6uf8YV zqeY@!7u;H|fGeHxET#>-^Dpo~?aXCl(CpS6t!~G^s zI%E}>jnS``J=MUfDJIt(nWQ!jPjmaa*lIp;k5qg13XKrDp!oqElF%G{%$KhPnCL8V zr6!hYk@fkrBDM}$R)lD|=5t1CqpO^Qf$tm+=KZ(pb8z7_@!Q+Z4O^{KjkAFPW~N%` zmqBhy!r&T7Oyuo1bW62f*C(0aLM4tdI8t$pQURNFOdAZ>g~4bjaE4Z +-- Copyright (C) 2014 Gracjan Polak + +-- 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 . + +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE FlexibleInstances #-} + +import Control.Monad (liftM) +import Data.List (nub, isPrefixOf) +import Data.Maybe (listToMaybe) +import Distribution.Compiler (CompilerFlavor(GHC)) +import Distribution.Package (PackageName(..),Dependency(..)) +import Distribution.PackageDescription (PackageDescription(..),allBuildInfo + ,BuildInfo(..) + ,usedExtensions,allLanguages + ,hcOptions + ,exeName) +import Distribution.PackageDescription.Configuration (flattenPackageDescription) +import Distribution.PackageDescription.Parse (readPackageDescription) +import Distribution.Simple.BuildPaths (defaultDistPref) +import Distribution.Verbosity (silent) +import Language.Haskell.Extension (Extension(..),Language(..)) +import System.Environment (getArgs) +import System.Exit (exitFailure) +import System.FilePath ((),dropFileName,normalise) + +data Sexp = SList [Sexp] + | SString String + | SSymbol String + +sym :: String -> Sexp +sym = SSymbol + +instance Show Sexp where + show (SSymbol s) = s + show (SString s) = show s -- Poor man's escaping + show (SList s) = "(" ++ unwords (map show s) ++ ")" + +class ToSexp a where + toSexp :: a -> Sexp + +instance ToSexp String where + toSexp = SString + +instance ToSexp Extension where + toSexp (EnableExtension ext) = toSexp (show ext) + toSexp (DisableExtension ext) = toSexp ("No" ++ show ext) + toSexp (UnknownExtension ext) = toSexp ext + +instance ToSexp Language where + toSexp (UnknownLanguage lang) = toSexp lang + toSexp lang = toSexp (show lang) + +instance ToSexp Dependency where + toSexp (Dependency (PackageName dependency) _) = toSexp dependency + +instance ToSexp Sexp where + toSexp = id + +cons :: (ToSexp a, ToSexp b) => a -> [b] -> Sexp +cons h t = SList (toSexp h : map toSexp t) + +getBuildDirectories :: PackageDescription -> FilePath -> [String] +getBuildDirectories pkgDesc cabalDir = case library pkgDesc of + Just _ -> buildDir : buildDirs + Nothing -> buildDirs + where distDir = cabalDir defaultDistPref + buildDir = distDir "build" + autogenDir = buildDir "autogen" + executableBuildDir e = buildDir exeName e (exeName e ++ "-tmp") + buildDirs = autogenDir : map executableBuildDir (executables pkgDesc) + +getSourceDirectories :: [BuildInfo] -> FilePath -> [String] +getSourceDirectories buildInfo cabalDir = + map (cabalDir ) (concatMap hsSourceDirs buildInfo) + +usefulOptions :: [String] +usefulOptions = ["-W", "-w", "-Wall", "-fglasgow-exts", "-fpackage-trust", "-fhelpful-errors", "-F", "-cpp"] + +usefulOptionPrefixes :: [String] +usefulOptionPrefixes = ["-fwarn-", "-fno-warn-", "-fcontext-stack=", "-firrefutable-tuples", "-D", "-U", "-I", "-fplugin=", "-fplugin-opt=", "-pgm", "-opt"] + +isFlycheckUsefulOption :: String -> Bool +isFlycheckUsefulOption opt = elem opt usefulOptions || any (`isPrefixOf` opt) usefulOptionPrefixes + +dumpPackageDescription :: PackageDescription -> FilePath -> Sexp +dumpPackageDescription pkgDesc cabalFile = SList [ + cons (sym "build-directories") buildDirs + , cons (sym "source-directories") sourceDirs + , cons (sym "extensions") exts + , cons (sym "languages") langs + , cons (sym "dependencies") deps + , cons (sym "other-options") otherOptions + ] + where cabalDir = dropFileName cabalFile + buildInfo = allBuildInfo pkgDesc + buildDirs = nub (map normalise (getBuildDirectories pkgDesc cabalDir)) + sourceDirs = nub (map normalise (getSourceDirectories buildInfo cabalDir)) + exts = nub (concatMap usedExtensions buildInfo) + langs = nub (concatMap allLanguages buildInfo) + deps = nub (buildDepends pkgDesc) + otherOptions = nub (filter isFlycheckUsefulOption (concatMap (hcOptions GHC) buildInfo)) + +dumpCabalConfiguration :: String -> IO () +dumpCabalConfiguration cabalFile = do + pkgDesc <- liftM flattenPackageDescription + (readPackageDescription silent cabalFile) + print (dumpPackageDescription pkgDesc cabalFile) + +main :: IO () +main = do + args <- getArgs + let cabalFile = listToMaybe args + maybe exitFailure dumpCabalConfiguration cabalFile diff --git a/profile/30_haskell.el b/profile/30_haskell.el index 1dbc76dd0..bd60f4442 100644 --- a/profile/30_haskell.el +++ b/profile/30_haskell.el @@ -12,6 +12,8 @@ (add-to-list 'ac-modes 'haskell-interactive-mode) (add-hook 'inferior-haskell-mode-hook 'ac-haskell-process-setup) + (with-eval-after-load 'flycheck + (add-hook 'flycheck-mode-hook 'flycheck-haskell-setup)) (defun haskell-mode-stylish-buffer-and-save-buffer() (interactive) diff --git a/profile/30_haskell.elc b/profile/30_haskell.elc index d9c1697ef9a16c66210bff3b588184c30a079354..a5f258fc774119d1ba7150b9e8cf282b585f3afb 100644 GIT binary patch delta 208 zcmeC=oWQj~m&rcH*vJrwjbfByj0_EcEMra}VFD6XMiwyzikP8@n8z3!8*GkZa$>Ac zElbSNO-w6EEz-@&PfSrr%c)GxNKMXGP>wcGP>L}&02*unw8j8zje)t6LUdwEif%@J zel}dKZf<@`Dw