Skip to content

Instantly share code, notes, and snippets.

@obadz
Last active December 27, 2017 05:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save obadz/eeb852fef550a1fba697 to your computer and use it in GitHub Desktop.
Save obadz/eeb852fef550a1fba697 to your computer and use it in GitHub Desktop.
{ packageOverrides ? (pkgs: {})
, haskellPackageOverrides ? (self: super: {
# mkDerivation = args: super.mkDerivation (args // {
# enableLibraryProfiling = true;
# # cabal configure --enable-executable-profiling --enable-library-profiling --ghc-options="-fprof-auto"
# });
# "ghc-mod" = super."ghc-mod".overrideDerivation (attrs: rec {
# src = pkgs.fetchFromGitHub {
# owner = "kazu-yamamoto";
# repo = "ghc-mod";
# rev = "e0044a3697b4ffa8c454c93c93711a3b1c0cc791";
# sha256 = "0i9h7kq23ss5afzdavwvh7h2abg9g6hcz2rwd9xyqbmm3k6ayrl1";
# };
# });
})
, config ? {
inherit packageOverrides haskellPackageOverrides;
allowBroken = true;
allowUnfree = true;
}
, nixpkgs ? import <nixpkgs> { inherit config; }
, pkgs ? nixpkgs.pkgs
, stdenv ? nixpkgs.stdenv
, lib ? stdenv.lib
, haskellPackages ? nixpkgs.haskellPackages
# , haskellPackages ? nixpkgs.haskell.packages.ghc7102.override { overrides = config.haskellPackageOverrides; }
# Tooling that is used for dev work but isn't
# needed for building. Editors, IDEs, etc.
, extraPackages ? (with pkgs; [
emacs
vim_configurable
git
gist
less
bash.doc # Need to pin that dependency otherwise nix-shell will need to download stuff after GC
cacert # For SSL cert below
])
, extraHaskellPackages ? (with haskellPackages; [
cabal2nix
cabal-install
ghc-mod
# ghci-ng
hasktags
# HaRe
hdevtools
hindent
hlint
# hoogle
# hsimport
# leksah
pointfree
stylish-haskell
])
, extraHaskellLibs ? (with haskellPackages; [
aeson
aeson-pretty
base
blaze-builder
bytestring
containers
errors
extra
http-types
http-client
http-client-tls
mtl
random
scientific
split
statistics
stdenv
text
time
transformers
unordered-containers
utf8-string
vector
wai
warp
])
# When noticing something gets downloaded after
# rebuilding, after a garbage collect, add here:
, extraPackagesToPin ? [
stdenv
]
# When set to true, built derivations will depend
# on extraPackages and extraPackagesToPin which will
# prevent tooling from getting garbage collected
, pinDependenciesFromGC ? true
}:
let drvs = rec {
packageA = haskellPackages.callPackage ./packageA {};
packageB = haskellPackages.callPackage ./packageB {};
# packageC depends on packageB
packageC = haskellPackages.callPackage ./packageC { inherit packageB; };
}; in
if lib.inNixShell
then
lib.mapAttrs (drvName: drv:
let drv' = pkgs.haskell.lib.addBuildDepends drv (extraPackages ++ extraHaskellPackages ++ extraHaskellLibs); in
lib.overrideDerivation drv'.env (attrs: {
shellHook = (attrs.shellHook or "") + ''
export PS1="Haskell ~ \u@\h:\w$ "
export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
'';
})) drvs
else if pinDependenciesFromGC
then
lib.mapAttrs (drvName: drv:
let drv' = pkgs.haskell.lib.addBuildDepends drv (extraPackages ++ extraHaskellPackages ++ extraHaskellLibs ++ extraPackagesToPin); in
lib.overrideDerivation drv' (attrs: {
postInstall = (attrs.postInstall or "") + ''
echo "$nativeBuildInputs" | xargs -n 1 >> "$out"/nix_dependencies.pindown
'';
})) drvs
else drvs
@obadz
Copy link
Author

obadz commented Jan 13, 2016

  • put your Haskell projects, 1 directory per project in $HOME/my/master/haskell/folder/projectA, ../projectB, ...
  • put the above snippet in $HOME/my/master/haskell/folder/default.nix
  • In each project folder, run cabal2nix . > default.nix (everytime you change the .cabal file). You need to do this in a nix-shell that has cabal2nix.
  • update the let drvs = { https://gist.github.com/obadz/eeb852fef550a1fba697#file-default-nix-L105 part to reference all your projects, taking care with dependencies
  • Add export NIX_PATH="$NIX_PATH:haskell=$HOME/my/master/haskell/folder" in your environment somehow
  • Then, to work on project a: nix-shell '<haskell>' -A projectA --pure
  • Or to just build the project nix-build '<haskell>' -A projectA

Nodes:

  • The extraHaskellLibs list is the packages you always want available in your shells. This means when you need a new package, you simply add it to .cabal file, invoke cabal2nix to keep default.nix in sync for the future, and then nudge some combo of M-x ghc-kill-process and invoking cabal configure should make things work. If the package is not on the list, you have to exit emacs, exit nix-shell, re-enter the shell and launch emacs from it.
  • If pinDependenciesFromGC = true, then everytime you build a project using this snippet, it will artificially depend ont all the extra packages and development tools you list in here. This makes sure that your entire dev environment doesn't get wiped everytime you nix-collect-garbage

@obadz
Copy link
Author

obadz commented Jan 14, 2016

Haskell/Nix relevant portions of my ~/.emacs

(defun filter (condp lst)
  (delq nil
        (mapcar (lambda (x) (and (funcall condp x) x)) lst)))

(mapcar (lambda (dir) (add-to-list 'load-path dir))
        (filter 'file-accessible-directory-p
                (mapcar (lambda (p) (concat p "/../share/emacs/site-lisp"))
                        (split-string (getenv "PATH") ":"))))

;; Haskell
(add-to-list 'load-path "~/.emacs.d/company-ghc/")
(require 'haskell-mode)
(require 'haskell-interactive-mode)
(require 'haskell-process)
(require 'ghc)
(require 'company)

; company mode
(add-to-list 'company-backends 'company-ghc)
(custom-set-variables '(company-ghc-show-info t))

(custom-set-variables
 '(haskell-process-suggest-remove-import-lines t)
 '(haskell-process-auto-import-loaded-modules t)
 '(haskell-process-log t)
 '(haskell-tags-on-save t)
 '(haskell-interactive-popup-errors nil))

(setq haskell-program-name "cabal repl")

; ghc-mod
(autoload 'ghc-init "ghc" nil t)
(autoload 'ghc-debug "ghc" nil t)

; doesn't work yet
(defun haskell-send-to-repl (start end)
  (interactive "r")
  (haskell-process-send-string (haskell-process) (buffer-substring start end)))

(defun haskell-insert-type-annotation ()
  (interactive)
  (haskell-process-do-type 't))

(defun haskell-mode-stylish-buffer-save ()
  (interactive)
  (save-buffer)
  (haskell-mode-stylish-buffer))

(add-hook 'haskell-mode-hook
          (lambda ()
            (rainbow-delimiters-mode)

            (interactive-haskell-mode)
            (turn-on-haskell-indent)

            (ghc-init)

            (company-mode)

            (local-set-key (kbd "C-SPC") 'company-complete)
            (local-set-key (kbd "<f2>") 'find-tag-no-prompt)
            (local-set-key (kbd "<f5>") 'haskell-mode-stylish-buffer-save)
            (local-set-key (kbd "<f6>") 'haskell-add-import)
            (local-set-key (kbd "<f8>") 'haskell-interactive-bring)
            (local-set-key (kbd "<f9>") 'haskell-process-load-or-reload)
            (local-set-key (kbd "<f11>") 'ghc-show-info)
            (local-set-key (kbd "<f12>") 'ghc-show-type)
            (local-set-key (kbd "<S-f12>") 'haskell-insert-type-annotation)
            ))

@obadz
Copy link
Author

obadz commented Apr 28, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment