mirror of
https://github.com/IHaskell/IHaskell.git
synced 2025-04-20 05:16:09 +00:00
Compare commits
No commits in common. "master" and "v0.6.2.0" have entirely different histories.
@ -1,30 +0,0 @@
|
||||
*.hi
|
||||
Untitled*.ipynb
|
||||
main/Main
|
||||
.stack-work
|
||||
notebooks/Test.ipynb
|
||||
notebooks/Untitled.ipynb
|
||||
notebooks/Untitled0.ipynb
|
||||
*.dyn_o
|
||||
*.dyn_hi
|
||||
*.o
|
||||
dist
|
||||
IHaskell/GHC
|
||||
env
|
||||
.shelly
|
||||
.ihaskell_capture
|
||||
.ipynb_checkpoints
|
||||
Hspec
|
||||
todo
|
||||
profile/profile.tar
|
||||
.cabal-sandbox
|
||||
cabal.sandbox.config
|
||||
.tmp1
|
||||
.tmp2
|
||||
.tmp3
|
||||
.stack-work
|
||||
src/Hspec
|
||||
notebooks
|
||||
dist
|
||||
**/dist
|
||||
**/.stack-work
|
3
.ghci
3
.ghci
@ -1,4 +1,5 @@
|
||||
:set -package ghc
|
||||
:set -package ghc-paths
|
||||
:set -optP-include -optPdist/build/autogen/cabal_macros.h
|
||||
:set -i. -isrc -idist/build/autogen
|
||||
:set prompt "\ESC[34mλ> \ESC[m"
|
||||
:set -XDoAndIfThenElse -XOverloadedStrings
|
||||
|
74
.github/workflows/docker.yml
vendored
74
.github/workflows/docker.yml
vendored
@ -1,74 +0,0 @@
|
||||
name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
paths:
|
||||
- '.dockerignore'
|
||||
- '.github/workflows/docker.yml'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- 'ghc-parser/**'
|
||||
- 'html/**'
|
||||
- 'ihaskell-display/**'
|
||||
- 'ihaskell.cabal'
|
||||
- 'ipython-kernel/**'
|
||||
- 'jupyterlab-ihaskell/**'
|
||||
- 'main/**'
|
||||
- 'src/**'
|
||||
- 'stack.yaml'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.dockerignore'
|
||||
- '.github/workflows/docker.yml'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- 'ghc-parser/**'
|
||||
- 'html/**'
|
||||
- 'ihaskell-display/**'
|
||||
- 'ihaskell.cabal'
|
||||
- 'ipython-kernel/**'
|
||||
- 'jupyterlab-ihaskell/**'
|
||||
- 'main/**'
|
||||
- 'src/**'
|
||||
- 'stack.yaml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: (github.event_name != 'pull_request' && ! github.event.pull_request.head.repo.fork) || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: haskell-actions/setup@v2
|
||||
name: Setup Haskell Stack
|
||||
with:
|
||||
enable-stack: true
|
||||
stack-version: "latest"
|
||||
|
||||
- name: Check Dockerfile GHC version matches
|
||||
run: |
|
||||
set -e
|
||||
STACK_GHC_VERSION=$(stack exec -- ghc --version | awk '{ print $NF }')
|
||||
DOCKER_GHC_VERSION=$(sed -n 's/ARG GHC_VERSION=\(.*\)/\1/p' Dockerfile)
|
||||
if [[ ${STACK_GHC_VERSION} != ${DOCKER_GHC_VERSION} ]]; then
|
||||
echo 'GHC_VERSION in Dockerfile does not match stack resolver'
|
||||
echo "GHC_VERSION should be ${STACK_GHC_VERSION}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- uses: elgohr/Publish-Docker-Github-Action@v5
|
||||
with:
|
||||
name: gibiansky/ihaskell
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
snapshot: true
|
||||
no_push: ${{ github.event_name == 'pull_request' }}
|
74
.github/workflows/nix.yml
vendored
74
.github/workflows/nix.yml
vendored
@ -1,74 +0,0 @@
|
||||
name: Nix
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'demo/**'
|
||||
- 'docker/**'
|
||||
- 'Dockerfile'
|
||||
- '.dockerignore'
|
||||
- '.ghci'
|
||||
- '.gitignore'
|
||||
- 'images/**'
|
||||
- 'notebooks/**'
|
||||
- 'stack/**'
|
||||
- 'README.md'
|
||||
- '*.yaml'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'demo/**'
|
||||
- 'docker/**'
|
||||
- 'Dockerfile'
|
||||
- '.dockerignore'
|
||||
- '.ghci'
|
||||
- '.gitignore'
|
||||
- 'images/**'
|
||||
- 'notebooks/**'
|
||||
- 'stack/**'
|
||||
- 'README.md'
|
||||
- '*.yaml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: (github.event_name != 'pull_request' && ! github.event.pull_request.head.repo.fork) || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork)
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
env:
|
||||
- ihaskell-env-ghc96
|
||||
- ihaskell-env-ghc98
|
||||
- ihaskell-env-ghc910
|
||||
|
||||
- ihaskell-env-display-ghc96
|
||||
- ihaskell-env-display-ghc98
|
||||
# - ihaskell-env-display-ghc910
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.22.1/install
|
||||
|
||||
- uses: cachix/cachix-action@v14
|
||||
with:
|
||||
name: ihaskell
|
||||
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
|
||||
- name: Build environment ${{matrix.env}}
|
||||
run: |
|
||||
nix build .#${{matrix.env}}
|
||||
|
||||
- name: Check acceptance test for ${{matrix.env}}
|
||||
# Don't bother running it with the display envs since we already run it
|
||||
# with the basic envs, and it doesn't test any display stuff.
|
||||
if: ${{ !(contains(matrix.env, fromJSON('"display"'))) }}
|
||||
run: |
|
||||
nix build .#checks.x86_64-linux.${{matrix.env}} -L
|
108
.github/workflows/stack-nix.yml
vendored
108
.github/workflows/stack-nix.yml
vendored
@ -1,108 +0,0 @@
|
||||
name: Stack (--nix)
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'demo/**'
|
||||
- 'docker/**'
|
||||
- 'Dockerfile'
|
||||
- '.dockerignore'
|
||||
- '.ghci'
|
||||
- '.gitignore'
|
||||
- 'images/**'
|
||||
- 'nix/**'
|
||||
- 'notebooks/**'
|
||||
- 'flake.nix'
|
||||
- 'flake.lock'
|
||||
- 'README.md'
|
||||
- 'README.md'
|
||||
- 'hie.yaml'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'demo/**'
|
||||
- 'docker/**'
|
||||
- 'Dockerfile'
|
||||
- '.dockerignore'
|
||||
- '.ghci'
|
||||
- '.gitignore'
|
||||
- 'images/**'
|
||||
- 'nix/**'
|
||||
- 'notebooks/**'
|
||||
- 'flake.nix'
|
||||
- 'flake.lock'
|
||||
- 'README.md'
|
||||
- 'README.md'
|
||||
- 'hie.yaml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
if: (github.event_name != 'pull_request' && ! github.event.pull_request.head.repo.fork) || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork)
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
stack-yaml:
|
||||
# - 'stack/stack-8.2.yaml'
|
||||
# - 'stack/stack-8.4.yaml'
|
||||
# - 'stack/stack-8.6.yaml'
|
||||
# - 'stack/stack-8.8.yaml'
|
||||
- 'stack/stack-8.10.yaml'
|
||||
- 'stack/stack-9.0.yaml'
|
||||
- 'stack/stack-9.2.yaml'
|
||||
- 'stack/stack-9.4.yaml'
|
||||
- 'stack/stack-9.6.yaml'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||
|
||||
- uses: haskell-actions/setup@v2
|
||||
name: Setup Haskell Stack
|
||||
with:
|
||||
enable-stack: true
|
||||
stack-version: "latest"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Cache Haskell dependencies
|
||||
with:
|
||||
path: |
|
||||
~/.stack/stack.sqlite3
|
||||
~/.stack/snapshots
|
||||
key: ${{ matrix.stack-yaml }}-nix-${{ hashFiles(format('./{0}', matrix.stack-yaml)) }}
|
||||
restore-keys: |
|
||||
${{ matrix.stack-yaml }}-nix-${{ hashFiles(format('./{0}', matrix.stack-yaml)) }}
|
||||
${{ matrix.stack-yaml }}-nix-
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
export "NIX_PATH=nixpkgs=$(nix run .#print-nixpkgs-master)"
|
||||
stack build --nix --stack-yaml ${{matrix.stack-yaml}}
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
export "NIX_PATH=nixpkgs=$(nix run .#print-nixpkgs-master)"
|
||||
stack test --nix --stack-yaml ${{matrix.stack-yaml}}
|
||||
|
||||
- name: Run integration test
|
||||
run: |
|
||||
set -e
|
||||
|
||||
export "NIX_PATH=nixpkgs=$(nix run .#print-nixpkgs-master)"
|
||||
|
||||
nix build .#jupyterlab
|
||||
export PATH="$(pwd)/result/bin:$(pwd)/.local/bin:$PATH"
|
||||
|
||||
stack install --nix --stack-yaml ${{matrix.stack-yaml}}
|
||||
|
||||
ihaskell install --stack --stack-flag="--nix" --stack-flag="--stack-yaml=$(realpath ${{matrix.stack-yaml}})"
|
||||
|
||||
# Ensure that IHaskell notebook remains unchanged.
|
||||
# Run the notebook to regenerate the outputs, then compare the new notebook to the old one.
|
||||
test/acceptance.nbconvert.sh jupyter nbconvert
|
110
.github/workflows/stack.yml
vendored
110
.github/workflows/stack.yml
vendored
@ -1,110 +0,0 @@
|
||||
name: Stack
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'demo/**'
|
||||
- 'docker/**'
|
||||
- 'Dockerfile'
|
||||
- '.dockerignore'
|
||||
- '.ghci'
|
||||
- '.gitignore'
|
||||
- 'images/**'
|
||||
- 'nix/**'
|
||||
- 'notebooks/**'
|
||||
- 'flake.nix'
|
||||
- 'flake.lock'
|
||||
- 'README.md'
|
||||
- 'hie.yaml'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'demo/**'
|
||||
- 'docker/**'
|
||||
- 'Dockerfile'
|
||||
- '.dockerignore'
|
||||
- '.ghci'
|
||||
- '.gitignore'
|
||||
- 'images/**'
|
||||
- 'nix/**'
|
||||
- 'notebooks/**'
|
||||
- 'flake.nix'
|
||||
- 'flake.lock'
|
||||
- 'README.md'
|
||||
- 'hie.yaml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
if: (github.event_name != 'pull_request' && ! github.event.pull_request.head.repo.fork) || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork)
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
stack-yaml:
|
||||
- 'stack/stack-8.4.yaml'
|
||||
- 'stack/stack-8.6.yaml'
|
||||
- 'stack/stack-8.8.yaml'
|
||||
- 'stack/stack-8.10.yaml'
|
||||
- 'stack/stack-9.0.yaml'
|
||||
- 'stack/stack-9.2.yaml'
|
||||
- 'stack/stack-9.4.yaml'
|
||||
- 'stack/stack-9.6.yaml'
|
||||
- 'stack.yaml'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: cachix/install-nix-action@v22
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||
|
||||
- uses: haskell-actions/setup@v2
|
||||
name: Setup Haskell Stack
|
||||
with:
|
||||
enable-stack: true
|
||||
stack-version: "latest"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Cache Haskell dependencies
|
||||
with:
|
||||
path: |
|
||||
~/.stack/stack.sqlite3
|
||||
~/.stack/snapshots
|
||||
key: ${{ matrix.stack-yaml }}-${{ hashFiles(format('./{0}', matrix.stack-yaml)) }}
|
||||
restore-keys: |
|
||||
${{ matrix.stack-yaml }}-${{ hashFiles(format('./{0}', matrix.stack-yaml)) }}
|
||||
${{ matrix.stack-yaml }}-
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libmagic-dev libgmp-dev libblas-dev liblapack-dev libcairo2-dev libpango1.0-dev libzmq3-dev jq
|
||||
|
||||
- name: Test ipython-kernel
|
||||
run: |
|
||||
stack build ipython-kernel --flag ipython-kernel:examples --stack-yaml ${{matrix.stack-yaml}}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
export "NIX_PATH=nixpkgs=$(nix run .#print-nixpkgs-master)"
|
||||
stack build ihaskell --stack-yaml ${{matrix.stack-yaml}}
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
stack test --stack-yaml ${{matrix.stack-yaml}}
|
||||
|
||||
- name: Run integration test
|
||||
run: |
|
||||
nix build .#jupyterlab
|
||||
export PATH="$(pwd)/result/bin:$(pwd)/.local/bin:$PATH"
|
||||
|
||||
stack install --stack-yaml ${{matrix.stack-yaml}}
|
||||
|
||||
ihaskell install --stack --stack-flag="--stack-yaml=$(realpath ${{matrix.stack-yaml}})"
|
||||
|
||||
# Ensure that IHaskell notebook remains unchanged.
|
||||
# Run the notebook to regenerate the outputs, then compare the new notebook to the old one.
|
||||
test/acceptance.nbconvert.sh jupyter nbconvert
|
23
.github/workflows/update-flake-lock.yml
vendored
23
.github/workflows/update-flake-lock.yml
vendored
@ -1,23 +0,0 @@
|
||||
name: Update flake.lock
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '1 1 * * 0'
|
||||
|
||||
jobs:
|
||||
lockfile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@v13
|
||||
- name: Update flake.lock
|
||||
uses: DeterminateSystems/update-flake-lock@v23
|
||||
with:
|
||||
pr-title: "Update `flake.lock`"
|
||||
pr-labels: |
|
||||
dependencies
|
||||
automated
|
||||
token: ${{ secrets.GH_TOKEN_FLAKE_LOCK_UPDATE }}
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,7 +1,4 @@
|
||||
*.hi
|
||||
Untitled*.ipynb
|
||||
main/Main
|
||||
.stack-work
|
||||
notebooks/Test.ipynb
|
||||
notebooks/Untitled.ipynb
|
||||
notebooks/Untitled0.ipynb
|
||||
@ -22,10 +19,3 @@ cabal.sandbox.config
|
||||
.tmp1
|
||||
.tmp2
|
||||
.tmp3
|
||||
stack.yaml.lock
|
||||
result
|
||||
default.nix
|
||||
dist-*/
|
||||
cabal.project.local
|
||||
cabal.config
|
||||
tsconfig.tsbuildinfo
|
||||
|
72
.travis.yml
Normal file
72
.travis.yml
Normal file
@ -0,0 +1,72 @@
|
||||
# Taken from multi-ghc-travis
|
||||
# NB: don't set `language: haskell` here
|
||||
|
||||
# The following enables several GHC versions to be tested; often it's enough to test only against the last release in a major GHC version. Feel free to omit lines listings versions you don't need/want testing for.
|
||||
env:
|
||||
- CABALVER=1.18 GHCVER=7.6.3
|
||||
- CABALVER=1.18 GHCVER=7.8.4 # see note about Alex/Happy for GHC >= 7.8
|
||||
- CABALVER=1.22 GHCVER=7.10.1
|
||||
# - CABALVER=head GHCVER=head # see section about GHC HEAD snapshots
|
||||
|
||||
# Note: the distinction between `before_install` and `install` is not important.
|
||||
before_install:
|
||||
- travis_retry sudo add-apt-repository -y ppa:hvr/ghc
|
||||
- travis_retry sudo apt-get update
|
||||
- travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER # see note about happy/alex
|
||||
- travis_retry sudo apt-get install libmagic-dev
|
||||
- travis_retry sudo apt-get install python3
|
||||
- travis_retry git clone http://www.github.com/zeromq/zeromq4-x.git libzmq
|
||||
- export OLDPWD=$(pwd) && cd libzmq && travis_retry ./autogen.sh && travis_retry ./configure && make && travis_retry sudo make install && travis_retry sudo ldconfig && cd $OLDPWD
|
||||
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.cabal/bin:$PATH
|
||||
- |
|
||||
if [ $GHCVER = "head" ] || [ ${GHCVER%.*} = "7.8" ] || [ ${GHCVER%.*} = "7.10" ]; then
|
||||
travis_retry sudo apt-get install happy-1.19.4 alex-3.1.3
|
||||
travis_retry sudo apt-get install libblas-dev liblapack-dev
|
||||
export PATH=/opt/alex/3.1.3/bin:/opt/happy/1.19.4/bin:$PATH
|
||||
else
|
||||
travis_retry sudo apt-get install happy alex
|
||||
fi
|
||||
|
||||
install:
|
||||
- cabal --version
|
||||
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
|
||||
- travis_retry cabal update
|
||||
- travis_retry cabal install cpphs
|
||||
- travis_retry cabal install gtk2hs-buildtools
|
||||
- |
|
||||
if [ ${GHCVER%.*} = "7.8" ]; then
|
||||
travis_retry cabal install arithmoi==0.4.* -fllvm
|
||||
travis_retry git clone http://www.github.com/gibiansky/hindent
|
||||
cd hindent && travis_retry cabal install && cd ..
|
||||
fi
|
||||
|
||||
# Here starts the actual work to be performed for the package under test; any command which exits with a non-zero exit code causes the build to fail.
|
||||
script:
|
||||
- |
|
||||
if [ ${GHCVER%.*} = "7.8" ] || [ ${GHCVER%.*} = "7.10" ]; then
|
||||
travis_retry ./build.sh all
|
||||
else
|
||||
travis_retry ./build.sh ihaskell
|
||||
fi
|
||||
# Build and run the test suite
|
||||
- travis_retry cabal install --only-dependencies --enable-tests
|
||||
- travis_retry cabal configure --enable-tests
|
||||
- |
|
||||
if [ ${GHCVER%.*} = "7.8" ]; then
|
||||
travis_retry cabal test --show-details=always
|
||||
fi
|
||||
- |
|
||||
if [ ${GHCVER%.*} = "7.8" ]; then
|
||||
./verify_formatting.py
|
||||
fi
|
||||
- cabal sdist
|
||||
|
||||
# The following scriptlet checks that the resulting source distribution can be built & installed
|
||||
- export SRC_TGZ=$(cabal info . | awk '{print $2 ".tar.gz";exit}') ;
|
||||
cd dist/;
|
||||
if [ -f "$SRC_TGZ" ]; then
|
||||
cabal install --force-reinstalls "$SRC_TGZ";
|
||||
else
|
||||
echo "expected '$SRC_TGZ' not found";
|
||||
exit 1;
|
||||
fi
|
96
Dockerfile
96
Dockerfile
@ -1,96 +0,0 @@
|
||||
# should match the GHC version of the stack.yaml resolver
|
||||
# checked in CI
|
||||
ARG GHC_VERSION=9.6.4
|
||||
|
||||
FROM haskell:${GHC_VERSION} AS ihaskell_base
|
||||
|
||||
# Install Ubuntu packages needed for IHaskell runtime
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libzmq5 \
|
||||
&& \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
FROM ihaskell_base AS builder
|
||||
|
||||
# Install Ubuntu packages needed for IHaskell build
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libzmq3-dev pkg-config \
|
||||
&& \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Build snapshot
|
||||
COPY stack.yaml stack.yaml
|
||||
COPY ihaskell.cabal ihaskell.cabal
|
||||
COPY ipython-kernel ipython-kernel
|
||||
COPY ghc-parser ghc-parser
|
||||
COPY ihaskell-display ihaskell-display
|
||||
RUN stack setup
|
||||
RUN stack build ihaskell --only-snapshot
|
||||
|
||||
# Build IHaskell itself.
|
||||
# Don't just `COPY .` so that changes in e.g. README.md don't trigger rebuild.
|
||||
COPY src src
|
||||
COPY html html
|
||||
COPY main main
|
||||
COPY jupyterlab-ihaskell jupyterlab-ihaskell
|
||||
COPY LICENSE LICENSE
|
||||
RUN stack install ihaskell --local-bin-path ./bin/
|
||||
|
||||
# Save resolver used to build IHaskell
|
||||
RUN sed -n 's/resolver: \(.*\)#.*/\1/p' stack.yaml | tee resolver.txt
|
||||
|
||||
# Save third-party data files
|
||||
RUN mkdir /data && \
|
||||
snapshot_install_root=$(stack path --snapshot-install-root) && \
|
||||
cp $(find ${snapshot_install_root} -name hlint.yaml) /data
|
||||
|
||||
FROM ihaskell_base AS ihaskell
|
||||
|
||||
# Install JupyterLab
|
||||
RUN apt-get update && \
|
||||
apt-get install -y python3-pip && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
RUN pip3 install -U pip
|
||||
RUN pip3 install -U jupyterlab notebook
|
||||
|
||||
# Create runtime user
|
||||
ENV NB_USER jovyan
|
||||
ENV NB_UID 1000
|
||||
RUN adduser --disabled-password \
|
||||
--gecos "Default user" \
|
||||
--uid ${NB_UID} \
|
||||
${NB_USER}
|
||||
|
||||
# Create directory for storing ihaskell files
|
||||
ENV IHASKELL_DATA_DIR /usr/local/lib/ihaskell
|
||||
RUN mkdir -p ${IHASKELL_DATA_DIR} && chown ${NB_UID} ${IHASKELL_DATA_DIR}
|
||||
|
||||
# Set up + set hlint data directory
|
||||
ENV HLINT_DATA_DIR /usr/local/lib/hlint
|
||||
COPY --from=builder --chown=${NB_UID} /data/hlint.yaml ${HLINT_DATA_DIR}/
|
||||
ENV hlint_datadir ${HLINT_DATA_DIR}
|
||||
|
||||
# Set current user + directory
|
||||
WORKDIR /home/${NB_USER}/src
|
||||
RUN chown -R ${NB_UID} /home/${NB_USER}/src
|
||||
USER ${NB_UID}
|
||||
|
||||
# Set up global project
|
||||
COPY --from=builder --chown=${NB_UID} /build/resolver.txt /tmp/
|
||||
RUN stack setup --resolver=$(cat /tmp/resolver.txt) --system-ghc
|
||||
RUN stack config set system-ghc --global true
|
||||
|
||||
# Set up env file
|
||||
RUN stack exec env --system-ghc > ${IHASKELL_DATA_DIR}/env
|
||||
|
||||
# Install + setup IHaskell
|
||||
COPY --from=builder --chown=${NB_UID} /build/bin/ihaskell /usr/local/bin/
|
||||
COPY --from=builder --chown=${NB_UID} /build/html ${IHASKELL_DATA_DIR}/html
|
||||
COPY --from=builder --chown=${NB_UID} /build/jupyterlab-ihaskell ${IHASKELL_DATA_DIR}/jupyterlab-ihaskell
|
||||
RUN export ihaskell_datadir=${IHASKELL_DATA_DIR} && \
|
||||
ihaskell install --env-file ${IHASKELL_DATA_DIR}/env
|
||||
RUN jupyter notebook --generate-config
|
||||
|
||||
CMD ["jupyter", "notebook", "--ip", "0.0.0.0"]
|
601
Hspec.hs
Normal file
601
Hspec.hs
Normal file
@ -0,0 +1,601 @@
|
||||
{-# LANGUAGE QuasiQuotes, OverloadedStrings, ExtendedDefaultRules, CPP #-}
|
||||
-- Keep all the language pragmas here so it can be compiled separately.
|
||||
module Main where
|
||||
import Prelude
|
||||
import GHC hiding (Qualified)
|
||||
import GHC.Paths
|
||||
import Data.IORef
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class ( MonadIO, liftIO )
|
||||
import Data.List
|
||||
import System.Directory
|
||||
import Shelly (Sh, shelly, cmd, (</>), toTextIgnore, cd, withTmpDir, mkdir_p,
|
||||
touchfile)
|
||||
import qualified Shelly
|
||||
import Control.Applicative ((<$>))
|
||||
import Filesystem.Path.CurrentOS (encodeString)
|
||||
import System.SetEnv (setEnv)
|
||||
import Data.String.Here
|
||||
import Data.String.Utils (strip, replace)
|
||||
import Data.Monoid
|
||||
|
||||
import IHaskell.Eval.Parser
|
||||
import IHaskell.Types
|
||||
import IHaskell.IPython
|
||||
import IHaskell.Eval.Evaluate as Eval hiding (liftIO)
|
||||
import qualified IHaskell.Eval.Evaluate as Eval (liftIO)
|
||||
|
||||
import IHaskell.Eval.Completion
|
||||
import IHaskell.Eval.ParseShell
|
||||
|
||||
import Debug.Trace
|
||||
|
||||
import Test.Hspec
|
||||
import Test.Hspec.HUnit
|
||||
import Test.HUnit (assertBool, assertFailure)
|
||||
|
||||
traceShowId x = traceShow x x
|
||||
|
||||
doGhc = runGhc (Just libdir)
|
||||
|
||||
parses str = do
|
||||
res <- doGhc $ parseString str
|
||||
return $ map unloc res
|
||||
|
||||
like parser desired = parser >>= (`shouldBe` desired)
|
||||
|
||||
is string blockType = do
|
||||
result <- doGhc $ parseString string
|
||||
map unloc result `shouldBe` [blockType $ strip string]
|
||||
|
||||
eval string = do
|
||||
outputAccum <- newIORef []
|
||||
pagerAccum <- newIORef []
|
||||
let publish evalResult = case evalResult of
|
||||
IntermediateResult {} -> return ()
|
||||
FinalResult outs page [] -> do
|
||||
modifyIORef outputAccum (outs :)
|
||||
modifyIORef pagerAccum (page :)
|
||||
|
||||
getTemporaryDirectory >>= setCurrentDirectory
|
||||
let state = defaultKernelState { getLintStatus = LintOff }
|
||||
interpret libdir False $ Eval.evaluate state string publish
|
||||
out <- readIORef outputAccum
|
||||
pagerOut <- readIORef pagerAccum
|
||||
return (reverse out, unlines . map extractPlain . reverse $ pagerOut)
|
||||
|
||||
evaluationComparing comparison string = do
|
||||
let indent (' ':x) = 1 + indent x
|
||||
indent _ = 0
|
||||
empty = null . strip
|
||||
stringLines = filter (not . empty) $ lines string
|
||||
minIndent = minimum (map indent stringLines)
|
||||
newString = unlines $ map (drop minIndent) stringLines
|
||||
eval newString >>= comparison
|
||||
|
||||
becomes string expected = evaluationComparing comparison string
|
||||
where
|
||||
comparison :: ([Display], String) -> IO ()
|
||||
comparison (results, pageOut) = do
|
||||
when (length results /= length expected) $
|
||||
expectationFailure $ "Expected result to have " ++ show (length expected)
|
||||
++ " results. Got " ++ show results
|
||||
|
||||
forM_ (zip results expected) $ \(ManyDisplay [Display result], expected) ->
|
||||
case extractPlain result of
|
||||
"" -> expectationFailure $ "No plain-text output in " ++ show result ++ "\nExpected: " ++ expected
|
||||
str -> str `shouldBe` expected
|
||||
|
||||
pages string expected = evaluationComparing comparison string
|
||||
where
|
||||
comparison (results, pageOut) =
|
||||
strip (stripHtml pageOut) `shouldBe` strip (unlines expected)
|
||||
|
||||
-- A very, very hacky method for removing HTML
|
||||
stripHtml str = go str
|
||||
where
|
||||
go ('<':str) = case stripPrefix "script" str of
|
||||
Nothing -> go' str
|
||||
Just str -> dropScriptTag str
|
||||
go (x:xs) = x : go xs
|
||||
go [] = []
|
||||
|
||||
go' ('>':str) = go str
|
||||
go' (x:xs) = go' xs
|
||||
go' [] = error $ "Unending bracket html tag in string " ++ str
|
||||
|
||||
dropScriptTag str = case stripPrefix "</script>" str of
|
||||
Just str -> go str
|
||||
Nothing -> dropScriptTag $ tail str
|
||||
|
||||
readCompletePrompt :: String -> (String, Int)
|
||||
-- | @readCompletePrompt "xs*ys"@ return @(xs, i)@ where i is the location of
|
||||
-- @'*'@ in the input string.
|
||||
readCompletePrompt string = case elemIndex '*' string of
|
||||
Nothing -> error "Expected cursor written as '*'."
|
||||
Just idx -> (replace "*" "" string, idx)
|
||||
|
||||
completes string expected = completionTarget newString cursorloc `shouldBe` expected
|
||||
where (newString, cursorloc) = readCompletePrompt string
|
||||
|
||||
completionEvent :: String -> Interpreter (String, [String])
|
||||
completionEvent string = complete newString cursorloc
|
||||
where (newString, cursorloc) = case elemIndex '*' string of
|
||||
Nothing -> error "Expected cursor written as '*'."
|
||||
Just idx -> (replace "*" "" string, idx)
|
||||
|
||||
completionEventInDirectory :: String -> IO (String, [String])
|
||||
completionEventInDirectory string
|
||||
= withHsDirectory $ const $ completionEvent string
|
||||
|
||||
|
||||
shouldHaveCompletionsInDirectory :: String -> [String] -> IO ()
|
||||
shouldHaveCompletionsInDirectory string expected = do
|
||||
(matched, completions) <- completionEventInDirectory string
|
||||
let existsInCompletion = (`elem` completions)
|
||||
unmatched = filter (not . existsInCompletion) expected
|
||||
expected `shouldBeAmong` completions
|
||||
|
||||
completionHas string expected
|
||||
= do (matched, completions) <- doGhc $ do initCompleter
|
||||
completionEvent string
|
||||
let existsInCompletion = (`elem` completions)
|
||||
unmatched = filter (not . existsInCompletion) expected
|
||||
expected `shouldBeAmong` completions
|
||||
|
||||
initCompleter :: Interpreter ()
|
||||
initCompleter = do
|
||||
flags <- getSessionDynFlags
|
||||
setSessionDynFlags $ flags { hscTarget = HscInterpreted, ghcLink = LinkInMemory }
|
||||
|
||||
-- Import modules.
|
||||
imports <- mapM parseImportDecl ["import Prelude",
|
||||
"import qualified Control.Monad",
|
||||
"import qualified Data.List as List",
|
||||
"import IHaskell.Display",
|
||||
"import Data.Maybe as Maybe"]
|
||||
setContext $ map IIDecl imports
|
||||
|
||||
inDirectory :: [Shelly.FilePath] -- ^ directories relative to temporary directory
|
||||
-> [Shelly.FilePath] -- ^ files relative to temporary directory
|
||||
-> (Shelly.FilePath -> Interpreter a)
|
||||
-> IO a
|
||||
-- | Run an Interpreter action, but first make a temporary directory
|
||||
-- with some files and folder and cd to it.
|
||||
inDirectory dirs files action = shelly $ withTmpDir $ \dirPath ->
|
||||
do cd dirPath
|
||||
mapM_ mkdir_p dirs
|
||||
mapM_ touchfile files
|
||||
liftIO $ doGhc $ wrap (encodeString dirPath) (action dirPath)
|
||||
where cdEvent path = liftIO $ setCurrentDirectory path --Eval.evaluate defaultKernelState (":! cd " ++ path) noPublish
|
||||
wrap :: FilePath -> Interpreter a -> Interpreter a
|
||||
wrap path action =
|
||||
do initCompleter
|
||||
pwd <- Eval.liftIO getCurrentDirectory
|
||||
cdEvent path -- change to the temporary directory
|
||||
out <- action -- run action
|
||||
cdEvent pwd -- change back to the original directory
|
||||
return out
|
||||
|
||||
withHsDirectory :: (Shelly.FilePath -> Interpreter a) -> IO a
|
||||
withHsDirectory = inDirectory ["" </> "dir", "dir" </> "dir1"]
|
||||
[""</> "file1.hs", "dir" </> "file2.hs",
|
||||
"" </> "file1.lhs", "dir" </> "file2.lhs"]
|
||||
|
||||
main :: IO ()
|
||||
main = hspec $ do
|
||||
parserTests
|
||||
evalTests
|
||||
completionTests
|
||||
|
||||
completionTests = do
|
||||
parseShellTests
|
||||
describe "Completion" $ do
|
||||
it "correctly gets the completion identifier without dots" $ do
|
||||
"hello*" `completes` ["hello"]
|
||||
"hello aa*bb goodbye" `completes` ["aa"]
|
||||
"hello aabb* goodbye" `completes` ["aabb"]
|
||||
"aacc* goodbye" `completes` ["aacc"]
|
||||
"hello *aabb goodbye" `completes` []
|
||||
"*aabb goodbye" `completes` []
|
||||
|
||||
it "correctly gets the completion identifier with dots" $ do
|
||||
"hello test.aa*bb goodbye" `completes` ["test", "aa"]
|
||||
"Test.*" `completes` ["Test", ""]
|
||||
"Test.Thing*" `completes` ["Test", "Thing"]
|
||||
"Test.Thing.*" `completes` ["Test", "Thing", ""]
|
||||
"Test.Thing.*nope" `completes` ["Test", "Thing", ""]
|
||||
|
||||
it "correctly gets the completion type" $ do
|
||||
completionType "import Data." 12 ["Data", ""] `shouldBe` ModuleName "Data" ""
|
||||
completionType "import Prel" 11 ["Prel"] `shouldBe` ModuleName "" "Prel"
|
||||
completionType "import D.B.M" 12 ["D", "B", "M"] `shouldBe` ModuleName "D.B" "M"
|
||||
completionType " import A." 10 ["A", ""] `shouldBe` ModuleName "A" ""
|
||||
completionType "import a.x" 10 ["a", "x"] `shouldBe` Identifier "x"
|
||||
completionType "A.x" 3 ["A", "x"] `shouldBe` Qualified "A" "x"
|
||||
completionType "a.x" 3 ["a", "x"] `shouldBe` Identifier "x"
|
||||
completionType "pri" 3 ["pri"] `shouldBe` Identifier "pri"
|
||||
completionType ":load A" 7 ["A"] `shouldBe` HsFilePath ":load A"
|
||||
"A"
|
||||
completionType ":! cd " 6 [""] `shouldBe` FilePath ":! cd " ""
|
||||
|
||||
|
||||
|
||||
it "properly completes identifiers" $ do
|
||||
"pri*" `completionHas` ["print"]
|
||||
"ma*" `completionHas` ["map"]
|
||||
"hello ma*" `completionHas` ["map"]
|
||||
"print $ catMa*" `completionHas` ["catMaybes"]
|
||||
|
||||
it "properly completes qualified identifiers" $ do
|
||||
"Control.Monad.liftM*" `completionHas` [ "Control.Monad.liftM"
|
||||
, "Control.Monad.liftM2"
|
||||
, "Control.Monad.liftM5"]
|
||||
"print $ List.intercal*" `completionHas` ["List.intercalate"]
|
||||
"print $ Data.Maybe.cat*" `completionHas` ["Data.Maybe.catMaybes"]
|
||||
"print $ Maybe.catM*" `completionHas` ["Maybe.catMaybes"]
|
||||
|
||||
it "properly completes imports" $ do
|
||||
"import Data.*" `completionHas` ["Data.Maybe", "Data.List"]
|
||||
"import Data.M*" `completionHas` ["Data.Maybe"]
|
||||
"import Prel*" `completionHas` ["Prelude"]
|
||||
|
||||
it "properly completes haskell file paths on :load directive" $
|
||||
let loading xs = ":load " ++ encodeString xs
|
||||
paths = map encodeString
|
||||
in do
|
||||
loading ("dir" </> "file*") `shouldHaveCompletionsInDirectory` paths ["dir" </> "file2.hs",
|
||||
"dir" </> "file2.lhs"]
|
||||
loading ("" </> "file1*") `shouldHaveCompletionsInDirectory` paths ["" </> "file1.hs",
|
||||
"" </> "file1.lhs"]
|
||||
loading ("" </> "file1*") `shouldHaveCompletionsInDirectory` paths ["" </> "file1.hs",
|
||||
"" </> "file1.lhs"]
|
||||
loading ("" </> "./*") `shouldHaveCompletionsInDirectory` paths ["./" </> "dir/"
|
||||
, "./" </> "file1.hs"
|
||||
, "./" </> "file1.lhs"]
|
||||
loading ("" </> "./*") `shouldHaveCompletionsInDirectory` paths ["./" </> "dir/"
|
||||
, "./" </> "file1.hs"
|
||||
, "./" </> "file1.lhs"]
|
||||
|
||||
it "provides path completions on empty shell cmds " $
|
||||
":! cd *" `shouldHaveCompletionsInDirectory` map encodeString ["" </> "dir/"
|
||||
, "" </> "file1.hs"
|
||||
, "" </> "file1.lhs"]
|
||||
|
||||
let withHsHome action = withHsDirectory $ \dirPath-> do
|
||||
home <- shelly $ Shelly.get_env_text "HOME"
|
||||
setHomeEvent dirPath
|
||||
result <- action
|
||||
setHomeEvent $ Shelly.fromText home
|
||||
return result
|
||||
setHomeEvent path = liftIO $ setEnv "HOME" (encodeString path)
|
||||
|
||||
it "correctly interprets ~ as the environment HOME variable" $
|
||||
let shouldHaveCompletions :: String -> [String] -> IO ()
|
||||
shouldHaveCompletions string expected = do
|
||||
(matched, completions) <- withHsHome $ completionEvent string
|
||||
let existsInCompletion = (`elem` completions)
|
||||
unmatched = filter (not . existsInCompletion) expected
|
||||
expected `shouldBeAmong` completions
|
||||
|
||||
in do
|
||||
":! cd ~/*" `shouldHaveCompletions` ["~/dir/"]
|
||||
":! ~/*" `shouldHaveCompletions` ["~/dir/"]
|
||||
":load ~/*" `shouldHaveCompletions` ["~/dir/"]
|
||||
":l ~/*" `shouldHaveCompletions` ["~/dir/"]
|
||||
|
||||
let shouldHaveMatchingText :: String -> String -> IO ()
|
||||
shouldHaveMatchingText string expected = do
|
||||
matchText <- withHsHome $ fst <$> uncurry complete (readCompletePrompt string)
|
||||
matchText `shouldBe` expected
|
||||
|
||||
setHomeEvent path = liftIO $ setEnv "HOME" (encodeString path)
|
||||
|
||||
it "generates the correct matchingText on `:! cd ~/*` " $
|
||||
do ":! cd ~/*" `shouldHaveMatchingText` ("~/" :: String)
|
||||
|
||||
it "generates the correct matchingText on `:load ~/*` " $
|
||||
do ":load ~/*" `shouldHaveMatchingText` ("~/" :: String)
|
||||
|
||||
it "generates the correct matchingText on `:l ~/*` " $
|
||||
do ":l ~/*" `shouldHaveMatchingText` ("~/" :: String)
|
||||
|
||||
evalTests = do
|
||||
describe "Code Evaluation" $ do
|
||||
it "evaluates expressions" $ do
|
||||
"3" `becomes` ["3"]
|
||||
"3+5" `becomes` ["8"]
|
||||
"print 3" `becomes` ["3"]
|
||||
[hereLit|
|
||||
let x = 11
|
||||
z = 10 in
|
||||
x+z
|
||||
|] `becomes` ["21"]
|
||||
|
||||
it "evaluates flags" $ do
|
||||
":set -package hello" `becomes` ["Warning: -package not supported yet"]
|
||||
":set -XNoImplicitPrelude" `becomes` []
|
||||
|
||||
it "evaluates multiline expressions" $ do
|
||||
[hereLit|
|
||||
import Control.Monad
|
||||
forM_ [1, 2, 3] $ \x ->
|
||||
print x
|
||||
|] `becomes` ["1\n2\n3"]
|
||||
|
||||
it "evaluates function declarations silently" $ do
|
||||
[hereLit|
|
||||
fun :: [Int] -> Int
|
||||
fun [] = 3
|
||||
fun (x:xs) = 10
|
||||
fun [1, 2]
|
||||
|] `becomes` ["10"]
|
||||
|
||||
it "evaluates data declarations" $ do
|
||||
[hereLit|
|
||||
data X = Y Int
|
||||
| Z String
|
||||
deriving (Show, Eq)
|
||||
print [Y 3, Z "No"]
|
||||
print (Y 3 == Z "No")
|
||||
|] `becomes` ["[Y 3,Z \"No\"]", "False"]
|
||||
|
||||
it "evaluates do blocks in expressions" $ do
|
||||
[hereLit|
|
||||
show (show (do
|
||||
Just 10
|
||||
Nothing
|
||||
Just 100))
|
||||
|] `becomes` ["\"\\\"Nothing\\\"\""]
|
||||
|
||||
it "is silent for imports" $ do
|
||||
"import Control.Monad" `becomes` []
|
||||
"import qualified Control.Monad" `becomes` []
|
||||
"import qualified Control.Monad as CM" `becomes` []
|
||||
"import Control.Monad (when)" `becomes` []
|
||||
|
||||
it "evaluates directives" $ do
|
||||
":typ 3" `becomes` ["3 :: forall a. Num a => a"]
|
||||
":k Maybe" `becomes` ["Maybe :: * -> *"]
|
||||
#if MIN_VERSION_ghc(7, 8, 0)
|
||||
":in String" `pages` ["type String = [Char] \t-- Defined in \8216GHC.Base\8217"]
|
||||
#else
|
||||
":in String" `pages` ["type String = [Char] \t-- Defined in `GHC.Base'"]
|
||||
#endif
|
||||
|
||||
parserTests = do
|
||||
layoutChunkerTests
|
||||
moduleNameTests
|
||||
parseStringTests
|
||||
|
||||
layoutChunkerTests = describe "Layout Chunk" $ do
|
||||
it "chunks 'a string'" $
|
||||
map unloc (layoutChunks "a string") `shouldBe` ["a string"]
|
||||
|
||||
it "chunks 'a\\n string'" $
|
||||
map unloc (layoutChunks "a\n string") `shouldBe` ["a\n string"]
|
||||
|
||||
it "chunks 'a\\n string\\nextra'" $
|
||||
map unloc (layoutChunks "a\n string\nextra") `shouldBe` ["a\n string","extra"]
|
||||
|
||||
it "chunks strings with too many lines" $
|
||||
map unloc (layoutChunks "a\n\nstring") `shouldBe` ["a","string"]
|
||||
|
||||
it "parses multiple exprs" $ do
|
||||
let text = [hereLit|
|
||||
first
|
||||
|
||||
second
|
||||
third
|
||||
|
||||
fourth
|
||||
|]
|
||||
layoutChunks text `shouldBe`
|
||||
[Located 2 "first",
|
||||
Located 4 "second",
|
||||
Located 5 "third",
|
||||
Located 7 "fourth"]
|
||||
|
||||
moduleNameTests = describe "Get Module Name" $ do
|
||||
it "parses simple module names" $
|
||||
"module A where\nx = 3" `named` ["A"]
|
||||
it "parses module names with dots" $
|
||||
"module A.B where\nx = 3" `named` ["A", "B"]
|
||||
it "parses module names with exports" $
|
||||
"module A.B.C ( x ) where x = 3" `named` ["A", "B", "C"]
|
||||
it "errors when given unnamed modules" $ do
|
||||
doGhc (getModuleName "x = 3") `shouldThrow` anyException
|
||||
where
|
||||
named str result = do
|
||||
res <- doGhc $ getModuleName str
|
||||
res `shouldBe` result
|
||||
|
||||
parseStringTests = describe "Parser" $ do
|
||||
it "parses empty strings" $
|
||||
parses "" `like` []
|
||||
|
||||
it "parses simple imports" $
|
||||
"import Data.Monoid" `is` Import
|
||||
|
||||
it "parses simple arithmetic" $
|
||||
"3 + 5" `is` Expression
|
||||
|
||||
it "parses :type" $
|
||||
parses ":type x\n:ty x" `like` [
|
||||
Directive GetType "x",
|
||||
Directive GetType "x"
|
||||
]
|
||||
|
||||
it "parses :info" $
|
||||
parses ":info x\n:in x" `like` [
|
||||
Directive GetInfo "x",
|
||||
Directive GetInfo "x"
|
||||
]
|
||||
|
||||
it "parses :help and :?" $
|
||||
parses ":? x\n:help x" `like` [
|
||||
Directive GetHelp "x",
|
||||
Directive GetHelp "x"
|
||||
]
|
||||
|
||||
it "parses :set x" $
|
||||
parses ":set x" `like` [
|
||||
Directive SetDynFlag "x"
|
||||
]
|
||||
|
||||
it "parses :extension x" $
|
||||
parses ":ex x\n:extension x" `like` [
|
||||
Directive SetExtension "x",
|
||||
Directive SetExtension "x"
|
||||
]
|
||||
|
||||
it "fails to parse :nope" $
|
||||
parses ":nope goodbye" `like` [
|
||||
ParseError (Loc 1 1) "Unknown directive: 'nope'."
|
||||
]
|
||||
|
||||
it "parses number followed by let stmt" $
|
||||
parses "3\nlet x = expr" `like` [
|
||||
Expression "3",
|
||||
Statement "let x = expr"
|
||||
]
|
||||
|
||||
it "parses let x in y" $
|
||||
"let x = 3 in x + 3" `is` Expression
|
||||
|
||||
it "parses a data declaration" $
|
||||
"data X = Y Int" `is` Declaration
|
||||
|
||||
it "parses number followed by type directive" $
|
||||
parses "3\n:t expr" `like` [
|
||||
Expression "3",
|
||||
Directive GetType "expr"
|
||||
]
|
||||
|
||||
it "parses a <- statement" $
|
||||
"y <- print 'no'" `is` Statement
|
||||
|
||||
it "parses a <- stmt followed by let stmt" $
|
||||
parses "y <- do print 'no'\nlet x = expr" `like` [
|
||||
Statement "y <- do print 'no'",
|
||||
Statement "let x = expr"
|
||||
]
|
||||
|
||||
it "parses <- followed by let followed by expr" $
|
||||
parses "y <- do print 'no'\nlet x = expr\nexpression" `like` [
|
||||
Statement "y <- do print 'no'",
|
||||
Statement "let x = expr",
|
||||
Expression "expression"
|
||||
]
|
||||
|
||||
it "parses two print statements" $
|
||||
parses "print yes\nprint no" `like` [
|
||||
Expression "print yes",
|
||||
Expression "print no"
|
||||
]
|
||||
|
||||
it "parses a pattern-maching function declaration" $
|
||||
"fun [] = 10" `is` Declaration
|
||||
|
||||
it "parses a function decl followed by an expression" $
|
||||
parses "fun [] = 10\nprint 'h'" `like` [
|
||||
Declaration "fun [] = 10",
|
||||
Expression "print 'h'"
|
||||
]
|
||||
|
||||
it "parses list pattern matching fun decl" $
|
||||
"fun (x : xs) = 100" `is` Declaration
|
||||
|
||||
it "parses two pattern matches as the same declaration" $
|
||||
"fun [] = 10\nfun (x : xs) = 100" `is` Declaration
|
||||
|
||||
it "parses a type signature followed by a declaration" $
|
||||
"fun :: [a] -> Int\nfun [] = 10\nfun (x : xs) = 100" `is` Declaration
|
||||
|
||||
it "parases a simple module" $
|
||||
"module A where x = 3" `is` Module
|
||||
|
||||
it "parses a module with an export" $
|
||||
"module B (x) where x = 3" `is` Module
|
||||
|
||||
it "breaks when a let is incomplete" $
|
||||
parses "let x = 3 in" `like` [
|
||||
ParseError (Loc 1 13) "parse error (possibly incorrect indentation or mismatched brackets)"
|
||||
]
|
||||
|
||||
it "breaks without data kinds" $
|
||||
parses "data X = 3" `like` [
|
||||
#if MIN_VERSION_ghc(7, 8, 0)
|
||||
ParseError (Loc 1 10) "Illegal literal in type (use DataKinds to enable): 3"
|
||||
#else
|
||||
ParseError (Loc 1 10) "Illegal literal in type (use -XDataKinds to enable): 3"
|
||||
#endif
|
||||
]
|
||||
|
||||
it "parses statements after imports" $ do
|
||||
parses "import X\nprint 3" `like` [
|
||||
Import "import X",
|
||||
Expression "print 3"
|
||||
]
|
||||
parses "import X\n\nprint 3" `like` [
|
||||
Import "import X",
|
||||
Expression "print 3"
|
||||
]
|
||||
it "ignores blank lines properly" $
|
||||
[hereLit|
|
||||
test arg = hello
|
||||
where
|
||||
x = y
|
||||
|
||||
z = w
|
||||
|] `is` Declaration
|
||||
it "doesn't break on long strings" $ do
|
||||
let longString = concat $ replicate 20 "hello "
|
||||
("img ! src \"" ++ longString ++ "\" ! width \"500\"") `is` Expression
|
||||
|
||||
it "parses do blocks in expression" $ do
|
||||
[hereLit|
|
||||
show (show (do
|
||||
Just 10
|
||||
Nothing
|
||||
Just 100))
|
||||
|] `is` Expression
|
||||
it "correctly locates parsed items" $ do
|
||||
let go = doGhc . parseString
|
||||
go [hereLit|
|
||||
first
|
||||
|
||||
second
|
||||
|] >>= (`shouldBe` [Located 2 (Expression "first"),
|
||||
Located 4 (Expression "second")])
|
||||
|
||||
|
||||
parseShellTests =
|
||||
describe "Parsing Shell Commands" $ do
|
||||
test "A" ["A"]
|
||||
test ":load A" [":load", "A"]
|
||||
test ":!l ~/Downloads/MyFile\\ Has\\ Spaces.txt"
|
||||
[":!l", "~/Downloads/MyFile\\ Has\\ Spaces.txt"]
|
||||
test ":!l \"~/Downloads/MyFile Has Spaces.txt\" /Another/File\\ WithSpaces.doc"
|
||||
[":!l", "~/Downloads/MyFile Has Spaces.txt", "/Another/File\\ WithSpaces.doc" ]
|
||||
where
|
||||
test string expected =
|
||||
it ("parses " ++ string ++ " correctly") $
|
||||
string `shouldParseTo` expected
|
||||
|
||||
shouldParseTo xs ys = fun ys (parseShell xs)
|
||||
where fun ys (Right xs') = xs' `shouldBe` ys
|
||||
fun ys (Left e) = assertFailure $ "parseShell returned error: \n" ++ show e
|
||||
|
||||
|
||||
-- Useful HSpec expectations ----
|
||||
---------------------------------
|
||||
|
||||
shouldBeAmong :: (Show a, Eq a) => [a] -> [a] -> Expectation
|
||||
-- |
|
||||
-- @sublist \`shouldbeAmong\` list@ sets the expectation that @sublist@ elements are
|
||||
-- among those in @list@.
|
||||
sublist `shouldBeAmong` list = assertBool errorMsg
|
||||
$ and [x `elem` list | x <- sublist]
|
||||
where
|
||||
errorMsg = show list ++ " doesn't contain " ++ show sublist
|
380
README.md
380
README.md
@ -1,227 +1,219 @@
|
||||
  [](https://github.com/gibiansky/IHaskell/actions?query=workflow%3ACI) [](https://mybinder.org/v2/gh/gibiansky/IHaskell/mybinder)
|
||||
### Status
|
||||
|
||||
[](https://gitter.im/gibiansky/IHaskell?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/gibiansky/IHaskell)
|
||||
|
||||

|
||||
|
||||
# IHaskell
|
||||
IHaskell is a kernel for the [Jupyter project](http://ipython.org), which allows you to use Haskell inside Jupyter frontends (including the console and notebook).
|
||||
|
||||
> You can now try IHaskell directly in your browser at [CoCalc](https://cocalc.com) or [mybinder.org](https://mybinder.org/v2/gh/gibiansky/IHaskell/mybinder).
|
||||
>
|
||||
> Alternatively, watch a [talk and demo](http://begriffs.com/posts/2016-01-20-ihaskell-notebook.html) showing off IHaskell features.
|
||||
|
||||
IHaskell is a kernel for the [Jupyter project](https://jupyter.org), which allows you to use Haskell inside Jupyter frontends (including the console and notebook). It currently supports GHC 8.4 through 9.10.
|
||||
|
||||
For a tour of some IHaskell features, check out the [demo Notebook](http://nbviewer.org/github/gibiansky/IHaskell/blob/master/notebooks/IHaskell.ipynb). More example notebooks are available on the [wiki](https://github.com/gibiansky/IHaskell/wiki).
|
||||
For a tour of some IHaskell features, check out the [demo Notebook](http://nbviewer.ipython.org/github/gibiansky/IHaskell/blob/master/notebooks/IHaskell.ipynb). More example notebooks are available on the [wiki](https://github.com/gibiansky/IHaskell/wiki).
|
||||
The [wiki](https://github.com/gibiansky/IHaskell/wiki) also has more extensive documentation of IHaskell features.
|
||||
|
||||
### Shell Usage
|
||||

|
||||

|
||||
|
||||
### Interactive In-Browser Notebook
|
||||

|
||||
|
||||
# Installation
|
||||
|
||||
## Linux
|
||||
# Source Installation
|
||||
|
||||
Some prerequisites; adapt to your distribution.
|
||||
**Note:** IHaskell does not support Windows. To use on Windows, install
|
||||
Virtualbox, install Ubuntu or another Linux distribution, and proceed with the
|
||||
install instructions.
|
||||
|
||||
**How to get help:** Feel free to open an issue [on Github](https://github.com/gibiansky/IHaskell/issues?direction=desc&sort=updated&state=open) or join the [Gitter channel](https://gitter.im/gibiansky/IHaskell?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge).
|
||||
|
||||
### Install Using Installation Scripts
|
||||
|
||||
#### Ubuntu:
|
||||
|
||||
If you are using a modern version of Ubuntu, clone the repository and then run the `ubuntu-install.sh` script:
|
||||
```bash
|
||||
sudo apt-get install -y python3-pip git libtinfo-dev libzmq3-dev libcairo2-dev libpango1.0-dev libmagic-dev libblas-dev liblapack-dev
|
||||
```
|
||||
|
||||
Install `stack`, clone this repository, install Python requirements, install
|
||||
`ihaskell`, and install the Jupyter kernelspec with `ihaskell`.
|
||||
|
||||
These instructions assume you don't already have Stack or a Jupyter
|
||||
installation, please skip the relevant steps if this is not the case.
|
||||
|
||||
```bash
|
||||
curl -sSL https://get.haskellstack.org/ | sh
|
||||
git clone https://github.com/gibiansky/IHaskell
|
||||
git clone http://www.github.com/gibiansky/IHaskell
|
||||
cd IHaskell
|
||||
pip3 install -r requirements.txt
|
||||
stack install --fast
|
||||
ihaskell install --stack
|
||||
./ubuntu-install.sh
|
||||
```
|
||||
This script will ask you for `sudo` permissions in order to install IHaskell dependencies. The script is readable and easy to inspect if you wish to know what it does before giving it root permissions.
|
||||
#### Mac OS X:
|
||||
|
||||
Run Jupyter.
|
||||
|
||||
On Mac OS X, clone the repository and then run the `macos-install.sh` script:
|
||||
```bash
|
||||
stack exec jupyter -- notebook
|
||||
```
|
||||
|
||||
## Mac
|
||||
|
||||
You need to have [Homebrew](https://brew.sh) installed.
|
||||
If you do not have it yet run `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"` in your terminal.
|
||||
|
||||
You also need the Xcode command line tools.
|
||||
You can install them by running `xcode-select --install` in the terminal and following the prompts.
|
||||
|
||||
These instructions assume you don't already have Stack or a Jupyter
|
||||
installation, please skip the relevant steps if this is not the case.
|
||||
|
||||
```bash
|
||||
brew install python3 zeromq libmagic cairo pkg-config haskell-stack pango
|
||||
git clone https://github.com/gibiansky/IHaskell
|
||||
git clone http://www.github.com/gibiansky/IHaskell
|
||||
cd IHaskell
|
||||
pip3 install -r requirements.txt
|
||||
stack install --fast
|
||||
ihaskell install --stack
|
||||
./macos-install.sh
|
||||
```
|
||||
Note that you must have [Homebrew](http://brew.sh/) installed for this script to work.
|
||||
|
||||
### Installing Manually
|
||||
|
||||
#### Install IPython
|
||||
Install IPython 3.0 or above:
|
||||
```bash
|
||||
pip install ipython[all]
|
||||
```
|
||||
This may require root permissions on some systems, in which case put a `sudo` before that command before running it.
|
||||
Once this is done, running `ipython --version` should print out `3.0` or above.
|
||||
|
||||
Note that IHaskell *requires* 3.0 or above; IHaskell *will not work* with IPython 2 or earlier.
|
||||
|
||||
#### Install Haskell
|
||||
Install GHC and Cabal. You must have appropriate versions of both:
|
||||
```bash
|
||||
ghc --numeric-version # Should be 7.6.* or 7.8.*
|
||||
cabal --version # Should be 1.18.* or newer
|
||||
```
|
||||
These may be installed in a number of ways, including the [Haskell Platform](http://www.haskell.org/platform/), as a [standalone Mac app](https://github.com/ghcformacosx/ghc-dot-app), via Homebrew with `brew install ghc cabal-install`, and so on.
|
||||
|
||||
#### Install ZeroMQ
|
||||
Install ZeroMQ, a library IHaskell uses for asynchronous communication.
|
||||
|
||||
- **Mac OS X**: With [Homebrew](http://brew.sh/) installed, run `brew install zeromq`. (If using 32-bit Haskell Platform, you *may* need to use `brew install zeromq --universal`. YMMV.)
|
||||
- **Ubuntu**: Run `sudo apt-get install libzmq3-dev`.
|
||||
- **Other**: You can install ZeroMQ from source or use another package manager:
|
||||
```bash
|
||||
# Compiling from source:
|
||||
git clone git@github.com:zeromq/zeromq4-x.git libzmq
|
||||
cd libzmq
|
||||
./autogen.sh && ./configure && make
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
```
|
||||
If your own platform has a package and I haven't included instructions for it, feel free to send me an email or a PR on this README.
|
||||
|
||||
#### Install Haskell Tools
|
||||
First, make sure that executables installed by `cabal` are on your shell `PATH`:
|
||||
```bash
|
||||
# If you have a ~/.cabal/bin folder:
|
||||
export PATH=~/.cabal/bin:$PATH
|
||||
|
||||
# If you have a ~/Library/Haskell/bin folder on OS X:
|
||||
export PATH=~/Library/Haskell/bin:$PATH
|
||||
```
|
||||
|
||||
If you have Homebrew installed to a location that `stack` does not expect (e.g. `/opt/homebrew`), you'd need to specify `--extra-include-dirs ${HOMEBREW_PREFIX}/include --extra-lib-dirs ${HOMEBREW_PREFIX}/lib` to the `stack` command.
|
||||
Then, install the `happy` parser generator tool and `cpphs` preprocessor:
|
||||
```bash
|
||||
cabal install happy cpphs
|
||||
```
|
||||
|
||||
Run Jupyter.
|
||||
#### Build IHaskell
|
||||
Install IHaskell! You may install it from Hackage via `cabal install`:
|
||||
```bash
|
||||
cabal install ihaskell --reorder-goals
|
||||
```
|
||||
As IHaskell updates frequently, you may also want to clone the repository and install from there:
|
||||
```bash
|
||||
git clone http://www.github.com/gibiansky/IHaskell
|
||||
cd IHaskell
|
||||
./build.sh ihaskell # Build and install IHaskell
|
||||
```
|
||||
|
||||
The build script, `build.sh`, is a script for building IHaskell and dependencies. It has the following modes:
|
||||
- `ihaskell`: Build and install `ihaskell` and the two dependencies from this repository, `ipython-kernel` and `ghc-parser`.
|
||||
- `quick`: Just install `ihaskell`, do not bother recompiling and reinstalling its dependencies (`ipython-kernel` and `ghc-parser`).
|
||||
- `display`: Install `ihaskell` and all the support libraries in `ihaskell-display/`.
|
||||
- `all`: Install everything, including `ihaskell`, the dependencies, and all the support libraries in `ihaskell-display/`.
|
||||
It is run via `./build.sh all` or equivalent.
|
||||
|
||||
IHaskell may also be built in a sandbox, via something like:
|
||||
```bash
|
||||
cd IHaskell
|
||||
cabal sandbox init
|
||||
cabal sandbox add-source ihaskell-display/* ghc-parser ipython-kernel
|
||||
cabal install . ihaskell-display/*
|
||||
```
|
||||
|
||||
You may also need to use `--extra-lib-dirs` and `--extra-include-dirs`, if
|
||||
`cabal` cannot find relevant libraries. For example:
|
||||
```bash
|
||||
cabal install . ihaskell-display/* --extra-lib-dirs=`brew --prefix libmagic`/lib --extra-include-dirs=`brew --prefix libmagic`/include
|
||||
```
|
||||
|
||||
#### Run IHaskell
|
||||
Run IHaskell:
|
||||
- `ihaskell install` to install the IHaskell kernel into Jupyter.
|
||||
- `ipython notebook` for the browser-based interactive notebook.
|
||||
- `ipython console --kernel haskell` for a REPL.
|
||||
|
||||
#### (Optional) Install Support Libraries
|
||||
|
||||
IHaskell comes with many support libraries, such as `ihaskell-diagrams`, `ihaskell-parsec`, and so on, which add rich and interactive displays for common libraries.
|
||||
You can install these with `cabal install`. To install all of them, clone this repository and run `./build.sh all` to install IHaskell and all of its display support libraries.
|
||||
|
||||
You may run into some issues with installing the `cairo` dependency on Macs. To fix this, you can install `gcc` via `brew` and then use it to install `cairo`:
|
||||
```bash
|
||||
brew install gcc49
|
||||
cabal install cairo --with-gcc=gcc-4.9
|
||||
```
|
||||
|
||||
### Gotchas
|
||||
|
||||
These are simply some problems have had and solutions to them.
|
||||
|
||||
**Problem**: You have Anaconda or Enthought or some other python distribution, and for unknown reasons IHaskell just hangs after the first input.
|
||||
|
||||
**Solution**: Anaconda and Enthought cause problems. Get rid of them.
|
||||
|
||||
**Problem**: You get an error when `pyzmq` is compiling that looks somewhat like
|
||||
```
|
||||
cc1: error: -Werror=unused-command-line-argument-hard-error-in-future: No option -Wunused-command-line-argument-hard-error-in-future
|
||||
```
|
||||
**Solution:** Rerun the command after changing the `ARCHFLAGS` variable via
|
||||
```bash
|
||||
export ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future
|
||||
```
|
||||
|
||||
**Problem**: You'd like to have IHaskell run some code every time it starts up, like `~/.ghci` or `~/.bashrc`.
|
||||
|
||||
**Solution**: IHaskell uses `~/.ihaskell/rc.hs` as its default configuration file; if you put code into that file (it may or may not exist), it will be loaded on startup. You can substitute a different file by passing the `--conf=myfile.hs` argument to `ihaskell install` to reconfigure the kernel.
|
||||
|
||||
**Note**: You may have some trouble due to browser caches with the notebook interface if you also use IPython's notebook interface or have used it in the past. If something doesn't work or IPython says it can't connect to the notebook server, make sure to clear the browser cache in whatever browser you're using, or try another browser.
|
||||
|
||||
# Contributing
|
||||
|
||||
IHaskell is a young project, and I'd love your help getting it to a stable and useful point. There's a lot to do, and if you'd like to contribute, feel free to get in touch with me via my email at andrew period gibiansky at gmail - although browsing the code should be enough to get you started, I'm more than happy to answer any questions myself.
|
||||
|
||||
**For package maintainers:** IHaskell has an ability to display data types it knows about with a rich format based on images or HTML. In order to do so, an external package `ihaskell-something` must be created and installed. Writing these packages is simply - they must just contain instance of the `IHaskellDisplay` typeclass, defined in `IHaskell.Display`, and for a package `ihaskell-something` should have a single module `IHaskell.Display.Something`. If you have a package with interesting data types that would benefit from a rich display format, please get in contact with me (andrew dot gibiansky at gmail) to write one of these packages! A sample package is available [here](https://github.com/gibiansky/IHaskell/tree/master/ihaskell-display/ihaskell-basic).
|
||||
|
||||
# Developer Notes
|
||||
|
||||
Before diving in, you should read the [brief description of IPython kernel architectures](http://andrew.gibiansky.com/blog/ipython/ipython-kernels/)
|
||||
and read the [complete messaging protocol specification](http://ipython.org/ipython-doc/dev/development/messaging.html).
|
||||
|
||||
|
||||
Please format your code with `hindent --style gibiansky` before submitting it; Travis CI automatically checks for code style before merging!
|
||||
|
||||
**Loading IHaskell into GHCi for testing:**
|
||||
|
||||
Use one of the methods below to access IHaskell files in GHCi. Once inside GHCi, you can load an IHaskell file; for example, `:load IHaskell/Config.hs`.
|
||||
|
||||
**Using cabal repl**
|
||||
|
||||
If you have the latest version of cabal (>v1.18.0), the simplest thing to do is
|
||||
|
||||
```bash
|
||||
stack exec jupyter -- notebook
|
||||
cd <path-to-IHaskell>
|
||||
cabal repl
|
||||
```
|
||||
|
||||
_Tested on macOS Sierra (10.12.6)_
|
||||
This will hide all packages not listed in `IHaskell.cabal`
|
||||
|
||||
## Windows
|
||||
**Using GHCi directly**
|
||||
|
||||
IHaskell does not support Windows, however it can be used on Windows 10 via
|
||||
Windows Subsystem for Linux (WSL). If WSL is not installed, follow the
|
||||
[Installation Guide for Windows 10](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
|
||||
The following assumes that Ubuntu is picked as the Linux distribution.
|
||||
|
||||
In the Ubuntu app, follow the steps above for Linux.
|
||||
|
||||
Jupyter Notebook is now ready to use. In the Ubuntu app, launch a Notebook
|
||||
Server, without opening the notebook in a browser:
|
||||
If you don't want to use `cabal repl`, you can just call ghci which can read the `.ghci` file included in the repository for the options.
|
||||
|
||||
```bash
|
||||
jupyter notebook --no-browser
|
||||
cd <path-to-IHaskell>
|
||||
chmod 600 .ghci # trust the .ghci file
|
||||
ghci
|
||||
```
|
||||
|
||||
Returning to Windows 10, open a browser and copy and paste the URL output in the
|
||||
step above (the token will differ).
|
||||
|
||||
```bash
|
||||
Or copy and paste one of these URLs:
|
||||
http://localhost:8888/?token=9ca8a725ddb1fdded176d9e0e675ba557ebb5fbef6c65fdf
|
||||
```
|
||||
|
||||
_Tested on Windows 10 (build 18362.175) with Ubuntu 18.04 on WSL_
|
||||
|
||||
Alternatively, install Virtualbox, install Ubuntu or another Linux distribution,
|
||||
and proceed with the install instructions.
|
||||
|
||||
## Docker
|
||||
|
||||
To quickly run a Jupyter notebook with the IHaskell kernel, try the `Dockerfile`
|
||||
in the top directory.
|
||||
|
||||
```bash
|
||||
docker build -t ihaskell:latest .
|
||||
docker run --rm -p 8888:8888 ihaskell:latest
|
||||
```
|
||||
|
||||
Or use the continuously updated Docker image
|
||||
[on Docker Hub](https://hub.docker.com/r/gibiansky/ihaskell).
|
||||
|
||||
```sh
|
||||
docker run --rm -p 8888:8888 gibiansky/ihaskell
|
||||
```
|
||||
|
||||
In order to mount your own local files into the Docker container
|
||||
use following command:
|
||||
|
||||
```sh
|
||||
docker run --rm -p 8888:8888 -v "$PWD":/home/jovyan/src gibiansky/ihaskell
|
||||
```
|
||||
|
||||
Be aware that the directory you're mounting must contain
|
||||
a `stack.yaml` file.
|
||||
A simple version would be:
|
||||
|
||||
```yaml
|
||||
resolver: lts-16.23
|
||||
packages: []
|
||||
```
|
||||
|
||||
It's recommended to use the same LTS version as the IHaskell image is using itself
|
||||
(as can be seen in [its stack.yaml](./stack.yaml)).
|
||||
This guarantees that stack doesn't have to first perform
|
||||
a lengthy installation of GHC before running your notebook.
|
||||
|
||||
You can also use the following script to run IHaskell in Docker: https://gist.github.com/brandonchinn178/928d6137bfd17961b9584a8f96c18827
|
||||
|
||||
## Nix
|
||||
|
||||
If you have the `nix` package manager installed, you can create an IHaskell
|
||||
notebook environment with one command. For example:
|
||||
|
||||
```bash
|
||||
$ nix-build -I nixpkgs=https://github.com/NixOS/nixpkgs/tarball/nixos-23.05 release.nix --argstr compiler ghc928 --arg packages "haskellPackages: [ haskellPackages.lens ]"
|
||||
<result path>
|
||||
$ <result path>/bin/jupyter notebook
|
||||
```
|
||||
|
||||
It might take a while the first time, but subsequent builds will be much
|
||||
faster. You can use the
|
||||
[https://ihaskell.cachix.org](https://app.cachix.org/cache/ihaskell) cache for
|
||||
prebuilt artifacts.
|
||||
|
||||
The IHaskell display modules are not loaded by default and have to be specified as additional packages:
|
||||
|
||||
```bash
|
||||
$ nix-build -I nixpkgs=https://github.com/NixOS/nixpkgs/tarball/nixos-23.05 release.nix --argstr compiler ghc928 --arg packages "haskellPackages: [ haskellPackages.ihaskell-blaze haskellPackages.ihaskell-charts ]"
|
||||
```
|
||||
|
||||
For more examples of using IHaskell with Nix, see https://github.com/vaibhavsagar/notebooks.
|
||||
|
||||
# Developing
|
||||
|
||||
IHaskell is regularly updated to work with the latest version of GHC. To read how this is done, and how the development environment is set up, please see [this blog post](https://vaibhavsagar.com/blog/2021/05/02/updating-ihaskell-newer-ghc).
|
||||
|
||||
## Nix flake
|
||||
|
||||
There is also a Nix flake that provides a developer environment. For details on Nix flakes, please see the documentation at https://wiki.nixos.org/wiki/Flakes.
|
||||
|
||||
After this, IHaskell can be compiled as follows:
|
||||
|
||||
```bash
|
||||
nix develop # This opens a new shell with all dependencies installed
|
||||
cabal update # Make sure Cabal's package index is up-to-date
|
||||
cabal build # Builds IHaskell
|
||||
```
|
||||
|
||||
Note that this shell also provides `haskell-language-server`, which can be used in your editor if it supports it. Opening your editor from within the `nix develop` shell should allow it to see `haskell-language-server`.
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
## Where are my packages? (IHaskell + Stack)
|
||||
|
||||
Stack manages separate environments for every package. By default your notebooks
|
||||
will only have access to a few packages that happen to be required for
|
||||
IHaskell. To make packages available add them to the stack.yaml in the IHaskell
|
||||
directory and run `stack install --fast`.
|
||||
|
||||
Packages should be added to the `packages:` section and can take the following
|
||||
form
|
||||
([reproduced here from the stack documentation](https://github.com/commercialhaskell/stack/blob/master/doc/yaml_configuration.md#packages)). If
|
||||
you've already installed a package by `stack install` you can simply list its
|
||||
name even if it's local.
|
||||
Then in the ghci session you can type things like:
|
||||
|
||||
```
|
||||
- package-name
|
||||
- location: .
|
||||
- location: dir1/dir2
|
||||
- location: https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
- location: http://github.com/yesodweb/wai/archive/2f8a8e1b771829f4a8a77c0111352ce45a14c30f.zip
|
||||
- location:
|
||||
git: git@github.com:commercialhaskell/stack.git
|
||||
commit: 6a86ee32e5b869a877151f74064572225e1a0398
|
||||
- location:
|
||||
hg: https://example.com/hg/repo
|
||||
commit: da39a3ee5e6b4b0d3255bfef95601890afd80709
|
||||
:set -package setenv
|
||||
:load src/Hspec.hs
|
||||
hspec parserTests
|
||||
:browse IHaskell.Types
|
||||
```
|
||||
|
||||
## The kernel keeps dying (IHaskell + Stack)
|
||||
|
||||
The default instructions globally install IHaskell with support for only one
|
||||
version of GHC. If you've e.g. installed an `lts-10` IHaskell and are using it
|
||||
with an `lts-9` project the mismatch between GHC 8.2 and GHC 8.0 will cause
|
||||
this error. Stack also has the notion of a 'global project' located at
|
||||
`~/.stack/global-project/` and the `stack.yaml` for that project should be on
|
||||
the same LTS as the version of IHaskell installed to avoid this issue.
|
||||
|
3
Setup.hs
3
Setup.hs
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
78
build.sh
Executable file
78
build.sh
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
print_help () {
|
||||
echo "Run build.sh from inside the ihaskell directory to install packages in this repository:"
|
||||
echo " ./build.sh ihaskell # Install ihaskell and its dependencies"
|
||||
echo " ./build.sh quick # Install ihaskell, but not its dependencies"
|
||||
echo " ./build.sh all # Install ihaskell, dependencies, and all display packages"
|
||||
echo " ./build.sh display # Install ihaskell and display libraries"
|
||||
echo
|
||||
echo "If this is your first time installing ihaskell, run './build.sh ihaskell'."
|
||||
}
|
||||
|
||||
# Verify that we're in the ihaskell directory.
|
||||
if [ ! -e ihaskell.cabal ]; then
|
||||
print_help;
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
print_help;
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! $1 = "all" ] && [ ! $1 = "ihaskell" ] && [ ! $1 = "display" ] && [ ! $1 = "quick" ]; then
|
||||
print_help;
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# What to install.
|
||||
INSTALLS=""
|
||||
|
||||
# Remove my kernelspec
|
||||
rm -rf ~/.ipython/kernels/haskell
|
||||
|
||||
# Compile dependencies.
|
||||
if [ $# -gt 0 ]; then
|
||||
if [ $1 = "all" ] || [ $1 = "ihaskell" ]; then
|
||||
INSTALLS="$INSTALLS ghc-parser ipython-kernel"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Always make ihaskell itself
|
||||
INSTALLS="$INSTALLS ."
|
||||
|
||||
# Install ihaskell-display packages.
|
||||
if [ $# -gt 0 ]; then
|
||||
if [ $1 = "display" ] || [ $1 = "all" ]; then
|
||||
# Install all the display libraries
|
||||
cd ihaskell-display
|
||||
for dir in `ls`
|
||||
do
|
||||
INSTALLS="$INSTALLS ihaskell-display/$dir"
|
||||
done
|
||||
cd ..
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean all required directories, just in case.
|
||||
TOP=`pwd`
|
||||
for pkg in $INSTALLS
|
||||
do
|
||||
cd ./$pkg
|
||||
cabal clean
|
||||
cd $TOP
|
||||
done
|
||||
|
||||
# Stick a "./" before everything.
|
||||
INSTALL_DIRS=`echo $INSTALLS | tr ' ' '\n' | sed 's#^#./#' | tr ' ' '\n'`
|
||||
|
||||
echo CMD: cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals
|
||||
cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals
|
||||
|
||||
if hash ihaskell 2>/dev/null; then
|
||||
ihaskell install 2>/dev/null || echo "The command \"ihaskell install\" failed. Please check your 'ipython --version'. 3.0 or up is required but it is $(ipython --version)!"
|
||||
else
|
||||
echo "Reminder: run 'ihaskell install' to install the IHaskell kernel to Jupyter."
|
||||
fi
|
@ -1,20 +0,0 @@
|
||||
packages: .
|
||||
./ipython-kernel
|
||||
./ghc-parser
|
||||
./ihaskell-display/ihaskell-aeson
|
||||
./ihaskell-display/ihaskell-blaze
|
||||
./ihaskell-display/ihaskell-charts
|
||||
./ihaskell-display/ihaskell-diagrams
|
||||
./ihaskell-display/ihaskell-gnuplot
|
||||
./ihaskell-display/ihaskell-graphviz
|
||||
./ihaskell-display/ihaskell-hatex
|
||||
./ihaskell-display/ihaskell-juicypixels
|
||||
./ihaskell-display/ihaskell-magic
|
||||
./ihaskell-display/ihaskell-plot
|
||||
./ihaskell-display/ihaskell-static-canvas
|
||||
./ihaskell-display/ihaskell-widgets
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/jeffreyrosenbluth/static-canvas.git
|
||||
tag: 1aad0f192828ded72dced14e42ac4e6baa6dab6f
|
2051
demo/Static Canvas IHaskell Display.html
Normal file
2051
demo/Static Canvas IHaskell Display.html
Normal file
File diff suppressed because one or more lines are too long
BIN
demo/doc-demo.png
Normal file
BIN
demo/doc-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
demo/hoogle-demo.png
Normal file
BIN
demo/hoogle-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
BIN
demo/info-demo.png
Normal file
BIN
demo/info-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
BIN
demo/json-demo.png
Normal file
BIN
demo/json-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
149
flake.lock
generated
149
flake.lock
generated
@ -1,149 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1733328505,
|
||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744298016,
|
||||
"narHash": "sha256-8zoVia97o0Fo1ADis9FLXdvkSbRN69o5fPgemqlfKdQ=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "c5c3ca4a992cc79e742bbfe9ee013467732d3aa4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-filter": {
|
||||
"locked": {
|
||||
"lastModified": 1731533336,
|
||||
"narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-filter",
|
||||
"rev": "f7653272fd234696ae94229839a99b73c9ab7de0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "nix-filter",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1739019272,
|
||||
"narHash": "sha256-7Fu7oazPoYCbDzb9k8D/DdbKrC3aU1zlnc39Y8jy/s8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "fa35a3c8e17a3de613240fea68f876e5b4896aec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs24_11": {
|
||||
"locked": {
|
||||
"lastModified": 1744492897,
|
||||
"narHash": "sha256-qqKO4FOo/vPmNIaRPcLqwfudUlQ29iNdI1IbCZfjmxs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "86484f6076aac9141df2bfcddbf7dcfce5e0c6bb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-24.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgsMaster": {
|
||||
"locked": {
|
||||
"lastModified": 1744514369,
|
||||
"narHash": "sha256-N9uWy2Ti5H5gYDoAPEcJ0i4dAbdQD9auJ2YjskbMqOc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ae29fc75d2d3ee07f88ce1a252d76964eb1efb24",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "master",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"hls": "hls",
|
||||
"nix-filter": "nix-filter",
|
||||
"nixpkgs24_11": "nixpkgs24_11",
|
||||
"nixpkgsMaster": "nixpkgsMaster"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
109
flake.nix
109
flake.nix
@ -1,109 +0,0 @@
|
||||
{
|
||||
description = "A Haskell kernel for IPython.";
|
||||
|
||||
inputs.nixpkgs24_11.url = "github:NixOS/nixpkgs/release-24.11";
|
||||
inputs.nixpkgsMaster.url = "github:NixOS/nixpkgs/master";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
inputs.hls = {
|
||||
url = "github:haskell/haskell-language-server";
|
||||
inputs.flake-utils.follows = "flake-utils";
|
||||
};
|
||||
inputs.nix-filter.url = "github:numtide/nix-filter";
|
||||
|
||||
nixConfig = {
|
||||
extra-substituters = [ "https://ihaskell.cachix.org" ];
|
||||
extra-trusted-public-keys = [ "ihaskell.cachix.org-1:WoIvex/Ft/++sjYW3ntqPUL3jDGXIKDpX60pC8d5VLM="];
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs24_11, nixpkgsMaster, flake-utils, hls, nix-filter, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system: let
|
||||
baseOverlay = _self: _super: { inherit nix-filter; };
|
||||
pkgsMaster = import nixpkgsMaster { inherit system; overlays = [baseOverlay]; };
|
||||
|
||||
jupyterlab = pkgsMaster.python3.withPackages (ps: [ ps.jupyterlab ps.notebook ]);
|
||||
|
||||
# Map from GHC version to release function
|
||||
versions = let
|
||||
mkVersion = pkgsSrc: compiler: overlays: extraArgs: {
|
||||
name = compiler;
|
||||
value = (import pkgsSrc { inherit system; overlays = [baseOverlay] ++ overlays; }).callPackage ./nix/release.nix ({
|
||||
inherit compiler;
|
||||
} // extraArgs);
|
||||
};
|
||||
in
|
||||
pkgsMaster.lib.listToAttrs [
|
||||
(mkVersion nixpkgs24_11 "ghc96" [(import ./nix/overlay-9.6.nix)] {})
|
||||
(mkVersion nixpkgs24_11 "ghc98" [(import ./nix/overlay-9.8.nix)] {})
|
||||
(mkVersion nixpkgsMaster "ghc910" [(import ./nix/overlay-9.10.nix)] {})
|
||||
];
|
||||
|
||||
# Helper function for building environments with a given set of packages
|
||||
mkEnvs = prefix: packages: pkgsMaster.lib.mapAttrs' (version: releaseFn: {
|
||||
name = prefix + version;
|
||||
value = (releaseFn {
|
||||
# Note: this can be changed to other Jupyter systems like jupyter-console
|
||||
extraEnvironmentBinaries = [ jupyterlab ];
|
||||
systemPackages = p: with p; [
|
||||
gnuplot # for the ihaskell-gnuplot runtime
|
||||
];
|
||||
inherit packages;
|
||||
});
|
||||
}) versions;
|
||||
|
||||
# Basic envs with Jupyterlab and IHaskell
|
||||
envs = mkEnvs "ihaskell-env-" (_: []);
|
||||
|
||||
# Envs with Jupyterlab, IHaskell, and all display packages
|
||||
displayEnvs = mkEnvs "ihaskell-env-display-" (p: with p; map (n: builtins.getAttr n p) (import ./nix/displays.nix));
|
||||
|
||||
# Executables only, pulled from passthru on the envs
|
||||
exes = pkgsMaster.lib.mapAttrs' (envName: env: {
|
||||
name = builtins.replaceStrings ["-env"] [""] envName;
|
||||
value = env.ihaskellExe;
|
||||
}) envs;
|
||||
|
||||
devShells = pkgsMaster.lib.mapAttrs' (version: releaseFn: {
|
||||
name = "ihaskell-dev-" + version;
|
||||
value = pkgsMaster.callPackage ./nix/mkDevShell.nix {
|
||||
inherit hls system version;
|
||||
haskellPackages = (releaseFn {}).haskellPackages;
|
||||
ihaskellOverlay = (releaseFn {}).ihaskellOverlay;
|
||||
};
|
||||
}) versions;
|
||||
|
||||
in {
|
||||
packages = envs // displayEnvs // exes // devShells // rec {
|
||||
# For easily testing that everything builds
|
||||
allEnvs = pkgsMaster.linkFarm "ihaskell-envs" envs;
|
||||
allDisplayEnvs = pkgsMaster.linkFarm "ihaskell-display-envs" displayEnvs;
|
||||
allExes = pkgsMaster.linkFarm "ihaskell-exes" exes;
|
||||
allDevShells = pkgsMaster.linkFarm "ihaskell-dev-shells" devShells;
|
||||
|
||||
# To use in CI
|
||||
inherit jupyterlab;
|
||||
print-nixpkgs-master = pkgsMaster.writeShellScriptBin "print-nixpkgs-master.sh" "echo ${pkgsMaster.path}";
|
||||
};
|
||||
|
||||
# Run the acceptance tests on each env
|
||||
checks = pkgsMaster.lib.mapAttrs (envName: env:
|
||||
pkgsMaster.stdenv.mkDerivation {
|
||||
name = envName + "-check";
|
||||
src = pkgsMaster.callPackage ./nix/ihaskell-src.nix {};
|
||||
nativeBuildInputs = with pkgsMaster; [jq bash];
|
||||
doCheck = true;
|
||||
checkPhase = ''
|
||||
mkdir -p home
|
||||
export HOME=$(pwd)/home
|
||||
bash ./test/acceptance.nbconvert.sh ${env}/bin/jupyter nbconvert
|
||||
'';
|
||||
installPhase = ''
|
||||
touch $out
|
||||
'';
|
||||
}
|
||||
) envs;
|
||||
|
||||
defaultPackage = self.packages.${system}.ihaskell-env-ghc96;
|
||||
|
||||
devShell = self.packages.${system}.ihaskell-dev-ghc96;
|
||||
});
|
||||
}
|
2187
ghc-parser/HaskellParser76.y.pp
Normal file
2187
ghc-parser/HaskellParser76.y.pp
Normal file
File diff suppressed because it is too large
Load Diff
2340
ghc-parser/HaskellParser782.y.pp
Normal file
2340
ghc-parser/HaskellParser782.y.pp
Normal file
File diff suppressed because it is too large
Load Diff
2340
ghc-parser/HaskellParser783.y.pp
Normal file
2340
ghc-parser/HaskellParser783.y.pp
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,8 @@
|
||||
import Distribution.Simple
|
||||
import Distribution.Simple
|
||||
import System.Cmd
|
||||
|
||||
main = defaultMain
|
||||
main = defaultMainWithHooks simpleUserHooks{
|
||||
preConf = \args confFlags -> do
|
||||
system "./build-parser.sh"
|
||||
preConf simpleUserHooks args confFlags
|
||||
}
|
||||
|
22
ghc-parser/build-parser.sh
Executable file
22
ghc-parser/build-parser.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash -e
|
||||
# Called from Setup.hs.
|
||||
|
||||
function make_parser {
|
||||
SRCDIR=$1
|
||||
SRCNAME=$2
|
||||
|
||||
# Preprocess the GHC parser we're using to CPP subs.
|
||||
cpphs --linepragma --text ${SRCNAME}.y.pp -OParser.y
|
||||
|
||||
# Compile the parser and remove intermediate file.
|
||||
happy Parser.y
|
||||
rm Parser.y
|
||||
|
||||
# Move output Haskell to source directory.
|
||||
mkdir -p $SRCDIR/Language/Haskell/GHC
|
||||
mv Parser.hs $SRCDIR/Language/Haskell/GHC/HappyParser.hs
|
||||
}
|
||||
|
||||
make_parser src-7.6 HaskellParser76
|
||||
make_parser src-7.8.2 HaskellParser782
|
||||
make_parser src-7.8.3 HaskellParser783
|
@ -1,6 +1,4 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveFunctor #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
module Language.Haskell.GHC.Parser (
|
||||
-- Parser handling
|
||||
runParser,
|
||||
@ -19,65 +17,24 @@ module Language.Haskell.GHC.Parser (
|
||||
parserTypeSignature,
|
||||
parserModule,
|
||||
parserExpression,
|
||||
parsePragmasIntoDynFlags,
|
||||
|
||||
-- Haskell string preprocessing.
|
||||
removeComments,
|
||||
layoutChunks,
|
||||
) where
|
||||
|
||||
import Data.List (intercalate, findIndex, isInfixOf)
|
||||
import Data.Char (isAlphaNum)
|
||||
import Data.List (intercalate, findIndex)
|
||||
|
||||
#if MIN_VERSION_ghc(9,8,0)
|
||||
import GHC.Driver.Config.Parser (initParserOpts)
|
||||
import GHC.Parser.Errors.Types (PsMessage(..))
|
||||
import GHC.Types.Error (defaultDiagnosticOpts, getMessages, MsgEnvelope(..))
|
||||
import GHC.Utils.Error (diagnosticMessage, formatBulleted)
|
||||
import GHC.Utils.Outputable (defaultSDocContext, renderWithContext)
|
||||
#elif MIN_VERSION_ghc(9,6,0)
|
||||
import GHC.Driver.Config.Parser (initParserOpts)
|
||||
import GHC.Parser.Errors.Types (PsMessage(..))
|
||||
import GHC.Types.Error (getMessages, MsgEnvelope(..))
|
||||
import GHC.Utils.Error (diagnosticMessage, defaultDiagnosticOpts, formatBulleted)
|
||||
import GHC.Utils.Outputable (defaultSDocContext, renderWithContext)
|
||||
#elif MIN_VERSION_ghc(9,4,0)
|
||||
import GHC.Driver.Config.Parser (initParserOpts)
|
||||
import GHC.Types.Error (diagnosticMessage, getMessages, MsgEnvelope(..))
|
||||
import GHC.Utils.Error (formatBulleted)
|
||||
import GHC.Utils.Outputable (defaultSDocContext)
|
||||
#elif MIN_VERSION_ghc(9,2,0)
|
||||
import GHC.Driver.Config (initParserOpts)
|
||||
import GHC.Parser.Errors.Ppr (pprError)
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_ghc(9,0,0)
|
||||
import GHC.Data.Bag
|
||||
import GHC.Driver.Session (parseDynamicFilePragma)
|
||||
import GHC.Data.FastString
|
||||
import GHC.Parser.Header (getOptions)
|
||||
import GHC.Parser.Lexer hiding (buffer)
|
||||
import GHC.Data.OrdList
|
||||
import GHC.Utils.Panic (handleGhcException)
|
||||
import qualified GHC.Types.SrcLoc as SrcLoc
|
||||
import GHC.Data.StringBuffer hiding (len)
|
||||
#else
|
||||
import Bag
|
||||
import DynFlags (parseDynamicFilePragma)
|
||||
import FastString
|
||||
import HeaderInfo (getOptions)
|
||||
import Lexer hiding (buffer)
|
||||
import OrdList
|
||||
import Panic (handleGhcException)
|
||||
import qualified SrcLoc as SrcLoc
|
||||
import StringBuffer hiding (len)
|
||||
#endif
|
||||
#if MIN_VERSION_ghc(8,10,0)
|
||||
#else
|
||||
import ErrUtils hiding (ErrMsg)
|
||||
#endif
|
||||
import FastString
|
||||
import GHC hiding (Located)
|
||||
import Lexer
|
||||
import OrdList
|
||||
import Outputable hiding ((<>))
|
||||
import SrcLoc hiding (Located)
|
||||
import StringBuffer
|
||||
|
||||
import GHC hiding (Located, Parsed, parser)
|
||||
import qualified Language.Haskell.GHC.HappyParser as Parse
|
||||
|
||||
-- | A line number in an input string.
|
||||
@ -111,29 +68,12 @@ data Located a = Located {
|
||||
data Parser a = Parser (P a)
|
||||
|
||||
-- Our parsers.
|
||||
parserStatement :: Parser (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
parserStatement = Parser Parse.fullStatement
|
||||
|
||||
parserImport :: Parser (LImportDecl GhcPs)
|
||||
parserImport = Parser Parse.fullImport
|
||||
|
||||
parserDeclaration :: Parser (OrdList (LHsDecl GhcPs))
|
||||
parserDeclaration = Parser Parse.fullDeclaration
|
||||
|
||||
parserExpression :: Parser (LHsExpr GhcPs)
|
||||
parserExpression = Parser Parse.fullExpression
|
||||
|
||||
parserTypeSignature :: Parser (SrcLoc.Located (OrdList (LHsDecl GhcPs)))
|
||||
parserTypeSignature = Parser Parse.fullTypeSignature
|
||||
|
||||
#if MIN_VERSION_ghc(9,6,0)
|
||||
parserModule :: Parser (SrcLoc.Located (HsModule GhcPs))
|
||||
#elif MIN_VERSION_ghc(9,0,0)
|
||||
parserModule :: Parser (SrcLoc.Located HsModule)
|
||||
#else
|
||||
parserModule :: Parser (SrcLoc.Located (HsModule GhcPs))
|
||||
#endif
|
||||
parserModule = Parser Parse.fullModule
|
||||
parserStatement = Parser Parse.fullStatement
|
||||
parserImport = Parser Parse.fullImport
|
||||
parserDeclaration = Parser Parse.fullDeclaration
|
||||
parserExpression = Parser Parse.fullExpression
|
||||
parserTypeSignature = Parser Parse.fullTypeSignature
|
||||
parserModule = Parser Parse.fullModule
|
||||
|
||||
-- | Run a GHC parser on a string. Return success or failure with
|
||||
-- associated information for both.
|
||||
@ -141,94 +81,47 @@ runParser :: DynFlags -> Parser a -> String -> ParseOutput a
|
||||
runParser flags (Parser parser) str =
|
||||
-- Create an initial parser state.
|
||||
let filename = "<interactive>"
|
||||
location = SrcLoc.mkRealSrcLoc (mkFastString filename) 1 1
|
||||
location = mkRealSrcLoc (mkFastString filename) 1 1
|
||||
buffer = stringToStringBuffer str
|
||||
#if MIN_VERSION_ghc(9,2,0)
|
||||
parseState = initParserState (initParserOpts flags) buffer location in
|
||||
#else
|
||||
parseState = mkPState flags buffer location in
|
||||
#endif
|
||||
-- Convert a GHC parser output into our own.
|
||||
toParseOut (unP parser parseState)
|
||||
toParseOut $ unP parser parseState
|
||||
where
|
||||
toParseOut :: ParseResult a -> ParseOutput a
|
||||
#if MIN_VERSION_ghc(9,4,0)
|
||||
toParseOut (PFailed pstate) =
|
||||
let realSpan = SrcLoc.psRealSpan $ last_loc pstate
|
||||
errMsg = printErrorBag (getMessages $ errors pstate)
|
||||
ln = srcLocLine $ SrcLoc.realSrcSpanStart realSpan
|
||||
col = srcLocCol $ SrcLoc.realSrcSpanStart realSpan
|
||||
in Failure errMsg $ Loc ln col
|
||||
#elif MIN_VERSION_ghc(9,2,0)
|
||||
toParseOut (PFailed pstate) =
|
||||
let realSpan = SrcLoc.psRealSpan $ last_loc pstate
|
||||
errMsg = printErrorBag (errors pstate)
|
||||
ln = srcLocLine $ SrcLoc.realSrcSpanStart realSpan
|
||||
col = srcLocCol $ SrcLoc.realSrcSpanStart realSpan
|
||||
in Failure errMsg $ Loc ln col
|
||||
#elif MIN_VERSION_ghc(9,0,0)
|
||||
toParseOut (PFailed pstate) =
|
||||
let realSpan = SrcLoc.psRealSpan $ last_loc pstate
|
||||
errMsg = printErrorBag $ snd $ (messages pstate) flags
|
||||
ln = srcLocLine $ SrcLoc.realSrcSpanStart realSpan
|
||||
col = srcLocCol $ SrcLoc.realSrcSpanStart realSpan
|
||||
in Failure errMsg $ Loc ln col
|
||||
#elif MIN_VERSION_ghc(8,10,0)
|
||||
toParseOut (PFailed pstate) =
|
||||
let realSpan = last_loc pstate
|
||||
errMsg = printErrorBag $ snd $ (messages pstate) flags
|
||||
ln = srcLocLine $ SrcLoc.realSrcSpanStart realSpan
|
||||
col = srcLocCol $ SrcLoc.realSrcSpanStart realSpan
|
||||
in Failure errMsg $ Loc ln col
|
||||
#else
|
||||
toParseOut (PFailed _ spn@(RealSrcSpan realSpan) err) =
|
||||
let errMsg = printErrorBag $ unitBag $ mkPlainErrMsg flags spn err
|
||||
ln = srcLocLine $ SrcLoc.realSrcSpanStart realSpan
|
||||
col = srcLocCol $ SrcLoc.realSrcSpanStart realSpan
|
||||
in Failure errMsg $ Loc ln col
|
||||
#endif
|
||||
toParseOut (PFailed span@(RealSrcSpan realSpan) err) =
|
||||
let errMsg = printErrorBag $ unitBag $ mkPlainErrMsg flags span err
|
||||
line = srcLocLine $ realSrcSpanStart realSpan
|
||||
col = srcLocCol $ realSrcSpanStart realSpan
|
||||
in Failure errMsg $ Loc line col
|
||||
|
||||
#if MIN_VERSION_ghc(8,10,0)
|
||||
#else
|
||||
toParseOut (PFailed _ spn err) =
|
||||
let errMsg = printErrorBag $ unitBag $ mkPlainErrMsg flags spn err
|
||||
toParseOut (PFailed span err) =
|
||||
let errMsg = printErrorBag $ unitBag $ mkPlainErrMsg flags span err
|
||||
in Failure errMsg $ Loc 0 0
|
||||
#endif
|
||||
|
||||
toParseOut (POk _parseState result) =
|
||||
Parsed result
|
||||
toParseOut (POk parseState result) =
|
||||
let parseEnd = realSrcSpanStart $ last_loc parseState
|
||||
endLine = srcLocLine parseEnd
|
||||
endCol = srcLocCol parseEnd
|
||||
(before, after) = splitAtLoc endLine endCol str
|
||||
in Parsed result
|
||||
|
||||
-- Convert the bag of errors into an error string.
|
||||
#if MIN_VERSION_ghc(9,8,0)
|
||||
printErrorBag bag = joinLines . map (renderWithContext defaultSDocContext . formatBulleted . diagnosticMessage (defaultDiagnosticOpts @PsMessage) . errMsgDiagnostic) $ bagToList bag
|
||||
#elif MIN_VERSION_ghc(9,6,0)
|
||||
printErrorBag bag = joinLines . map (renderWithContext defaultSDocContext . formatBulleted defaultSDocContext . diagnosticMessage (defaultDiagnosticOpts @PsMessage) . errMsgDiagnostic) $ bagToList bag
|
||||
#elif MIN_VERSION_ghc(9,4,0)
|
||||
printErrorBag bag = joinLines . map (show . formatBulleted defaultSDocContext . diagnosticMessage . errMsgDiagnostic) $ bagToList bag
|
||||
#elif MIN_VERSION_ghc(9,2,0)
|
||||
printErrorBag bag = joinLines . map (show . pprError) $ bagToList bag
|
||||
#else
|
||||
printErrorBag bag = joinLines . map show $ bagToList bag
|
||||
#endif
|
||||
|
||||
-- Taken from http://blog.shaynefletcher.org/2019/06/have-ghc-parsing-respect-dynamic-pragmas.html
|
||||
parsePragmasIntoDynFlags :: DynFlags -> FilePath -> String -> IO (Maybe DynFlags)
|
||||
parsePragmasIntoDynFlags flags filepath str =
|
||||
catchErrors $ do
|
||||
#if MIN_VERSION_ghc(9,4,0)
|
||||
let opts = snd $ getOptions (initParserOpts flags) (stringToStringBuffer str) filepath
|
||||
#else
|
||||
let opts = getOptions flags (stringToStringBuffer str) filepath
|
||||
#endif
|
||||
(flags', _, _) <- parseDynamicFilePragma flags opts
|
||||
return $ Just flags'
|
||||
-- | Split a string at a given line and column. The column is included in
|
||||
-- the second part of the split.
|
||||
splitAtLoc :: LineNumber -> ColumnNumber -> String -> (String, String)
|
||||
splitAtLoc line col string =
|
||||
if line > length (lines string)
|
||||
then (string, "")
|
||||
else (before, after)
|
||||
where
|
||||
catchErrors :: IO (Maybe DynFlags) -> IO (Maybe DynFlags)
|
||||
catchErrors act =
|
||||
handleGhcException reportErr (handleSourceError reportErr act)
|
||||
reportErr e = do
|
||||
putStrLn $ "error : " ++ show e
|
||||
return Nothing
|
||||
(beforeLines, afterLines) = splitAt line $ lines string
|
||||
theLine = last beforeLines
|
||||
(beforeChars, afterChars) = splitAt (col - 1) theLine
|
||||
|
||||
before = joinLines (init beforeLines) ++ '\n' : beforeChars
|
||||
after = joinLines $ afterChars : afterLines
|
||||
|
||||
-- Not the same as 'unlines', due to trailing \n
|
||||
joinLines :: [String] -> String
|
||||
@ -238,13 +131,11 @@ joinLines = intercalate "\n"
|
||||
-- A chunk is a line and all lines immediately following that are indented
|
||||
-- beyond the indentation of the first line. This parses Haskell layout
|
||||
-- rules properly, and allows using multiline expressions via indentation.
|
||||
--
|
||||
-- Quasiquotes are allowed via a post-processing step.
|
||||
layoutChunks :: String -> [Located String]
|
||||
layoutChunks = joinQuasiquotes . go 1
|
||||
layoutChunks = go 1
|
||||
where
|
||||
go :: LineNumber -> String -> [Located String]
|
||||
go ln = filter (not . null . unloc) . map (fmap strip) . layoutLines ln . lines
|
||||
go line = filter (not . null . unloc) . map (fmap strip) . layoutLines line . lines
|
||||
|
||||
-- drop spaces on left and right
|
||||
strip = dropRight . dropLeft
|
||||
@ -258,13 +149,13 @@ layoutChunks = joinQuasiquotes . go 1
|
||||
layoutLines _ [] = []
|
||||
|
||||
-- Use the indent of the first line to find the end of the first block.
|
||||
layoutLines lineIdx xs@(firstLine:rest) =
|
||||
layoutLines lineIdx all@(firstLine:rest) =
|
||||
let firstIndent = indentLevel firstLine
|
||||
blockEnded ln = indentLevel ln <= firstIndent in
|
||||
blockEnded line = indentLevel line <= firstIndent in
|
||||
case findIndex blockEnded rest of
|
||||
-- If the first block doesn't end, return the whole string, since
|
||||
-- that just means the block takes up the entire string.
|
||||
Nothing -> [Located lineIdx $ intercalate "\n" xs]
|
||||
Nothing -> [Located lineIdx $ intercalate "\n" all]
|
||||
|
||||
-- We found the end of the block. Split this bit out and recurse.
|
||||
Just idx ->
|
||||
@ -283,7 +174,6 @@ layoutChunks = joinQuasiquotes . go 1
|
||||
|
||||
indentLevel _ = 0
|
||||
|
||||
|
||||
-- | Drop comments from Haskell source.
|
||||
-- Simply gets rid of them, does not replace them in any way.
|
||||
removeComments :: String -> String
|
||||
@ -306,7 +196,6 @@ removeComments = removeOneLineComments . removeMultilineComments 0 0
|
||||
where
|
||||
dropLine = removeOneLineComments . dropWhile (/= '\n')
|
||||
|
||||
removeMultilineComments :: Int -> Int -> String -> String
|
||||
removeMultilineComments nesting pragmaNesting str =
|
||||
case str of
|
||||
-- Don't remove comments after cmd directives
|
||||
@ -347,44 +236,7 @@ removeComments = removeOneLineComments . removeMultilineComments 0 0
|
||||
|
||||
-- Take a part of a string that ends in an unescaped quote.
|
||||
takeString str = case str of
|
||||
escaped@('\\':'"':_) -> escaped
|
||||
'"':_ -> "\""
|
||||
escaped@('\\':'"':rest) -> escaped
|
||||
'"':rest -> "\""
|
||||
x:xs -> x:takeString xs
|
||||
[] -> []
|
||||
|
||||
|
||||
-- | Post processing step to combine quasiquoted blocks into single blocks.
|
||||
-- This is necessary because quasiquoted blocks don't follow normal indentation rules.
|
||||
joinQuasiquotes :: [Located String] -> [Located String]
|
||||
joinQuasiquotes = reverse . joinQuasiquotes' . reverse
|
||||
where
|
||||
-- This operates by finding |] and then joining blocks until a line
|
||||
-- that has some corresponding [...|. This is still a hack, but close to
|
||||
-- good enough.
|
||||
joinQuasiquotes' [] = []
|
||||
joinQuasiquotes' (block:blocks) =
|
||||
if "|]" `isInfixOf` unloc block
|
||||
then
|
||||
let (pieces, rest) = break (hasQuasiquoteStart . unloc) blocks
|
||||
in case rest of
|
||||
[] -> block : joinQuasiquotes' blocks
|
||||
startBlock:blocks' ->
|
||||
concatBlocks (block : pieces ++ [startBlock]) : joinQuasiquotes blocks'
|
||||
else block : joinQuasiquotes' blocks
|
||||
|
||||
-- Combine a lit of reversed blocks into a single, non-reversed block.
|
||||
concatBlocks :: [Located String] -> Located String
|
||||
concatBlocks blocks = Located (line $ last blocks) $ joinLines $ map unloc $ reverse blocks
|
||||
|
||||
-- Does this string have a [...| in it?
|
||||
hasQuasiquoteStart :: String -> Bool
|
||||
hasQuasiquoteStart str =
|
||||
case break (== '[') str of
|
||||
(_, "") -> False
|
||||
(_, _:rest) ->
|
||||
case break (== '|') rest of
|
||||
(_, "") -> False
|
||||
(chars, _) -> all isIdentChar chars
|
||||
|
||||
isIdentChar :: Char -> Bool
|
||||
isIdentChar c = isAlphaNum c || c == '_' || c == '\''
|
||||
|
@ -2,43 +2,46 @@
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
name: ghc-parser
|
||||
version: 0.2.7.0
|
||||
version: 0.1.6.0
|
||||
synopsis: Haskell source parser from GHC.
|
||||
-- description:
|
||||
homepage: https://github.com/IHaskell/IHaskell
|
||||
homepage: https://github.com/gibiansky/IHaskell
|
||||
license: MIT
|
||||
license-file: LICENSE
|
||||
author: Andrew Gibiansky
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
-- copyright:
|
||||
category: Language
|
||||
build-type: Simple
|
||||
build-type: Custom
|
||||
-- extra-source-files:
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
extra-source-files:
|
||||
build-parser.sh
|
||||
HaskellParser76.y.pp
|
||||
HaskellParser782.y.pp
|
||||
HaskellParser783.y.pp
|
||||
src-7.10/Language/Haskell/GHC/HappyParser.hs
|
||||
|
||||
library
|
||||
ghc-options: -Wall
|
||||
build-tools: happy, cpphs
|
||||
exposed-modules: Language.Haskell.GHC.Parser,
|
||||
Language.Haskell.GHC.HappyParser
|
||||
-- other-modules:
|
||||
-- other-extensions:
|
||||
build-depends: base >=4.9 && < 5,
|
||||
ghc >=8.4 && <9.11
|
||||
|
||||
if impl(ghc >= 8.4) && impl(ghc < 8.10)
|
||||
hs-source-dirs: generic-src src-8.4
|
||||
if impl(ghc >= 8.10) && impl(ghc < 9.0)
|
||||
hs-source-dirs: generic-src src-8.10
|
||||
if impl(ghc >= 9.0) && impl(ghc < 9.2)
|
||||
hs-source-dirs: generic-src src-9.0
|
||||
if impl(ghc >= 9.2) && impl(ghc < 9.4)
|
||||
hs-source-dirs: generic-src src-9.2
|
||||
if impl(ghc >= 9.4) && impl(ghc < 9.6)
|
||||
hs-source-dirs: generic-src src-9.4
|
||||
if impl(ghc >= 9.6) && impl(ghc < 9.8)
|
||||
hs-source-dirs: generic-src src-9.6
|
||||
if impl(ghc >= 9.8) && impl(ghc < 9.12)
|
||||
hs-source-dirs: generic-src src-9.8
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
ghc >=7.6 && <7.11
|
||||
|
||||
if impl(ghc >= 7.6) && impl(ghc < 7.8)
|
||||
hs-source-dirs: generic-src src-7.6
|
||||
else
|
||||
if impl(ghc >= 7.8) && impl(ghc < 7.8.3)
|
||||
hs-source-dirs: generic-src src-7.8.2
|
||||
else
|
||||
if impl(ghc < 7.10)
|
||||
hs-source-dirs: generic-src src-7.8.3
|
||||
else
|
||||
hs-source-dirs: generic-src src-7.10
|
||||
|
||||
default-language: Haskell2010
|
||||
|
42
ghc-parser/src-7.10/Language/Haskell/GHC/HappyParser.hs
Normal file
42
ghc-parser/src-7.10/Language/Haskell/GHC/HappyParser.hs
Normal file
@ -0,0 +1,42 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import Parser
|
||||
import SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import HsSyn
|
||||
|
||||
-- compiler/utils
|
||||
import OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import RdrHsSyn
|
||||
import Lexer
|
||||
|
||||
-- compiler/basicTypes
|
||||
import RdrName
|
||||
|
||||
fullStatement :: P (Maybe (LStmt RdrName (LHsExpr RdrName)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl RdrName)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl RdrName))
|
||||
fullDeclaration = parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr RdrName)
|
||||
fullExpression = parseExpression
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl RdrName)))
|
||||
fullTypeSignature = parseTypeSignature
|
||||
|
||||
fullModule :: P (Located (HsModule RdrName))
|
||||
fullModule = parseModule
|
26902
ghc-parser/src-7.6/Language/Haskell/GHC/HappyParser.hs
Normal file
26902
ghc-parser/src-7.6/Language/Haskell/GHC/HappyParser.hs
Normal file
File diff suppressed because it is too large
Load Diff
29626
ghc-parser/src-7.8.2/Language/Haskell/GHC/HappyParser.hs
Normal file
29626
ghc-parser/src-7.8.2/Language/Haskell/GHC/HappyParser.hs
Normal file
File diff suppressed because it is too large
Load Diff
29626
ghc-parser/src-7.8.3/Language/Haskell/GHC/HappyParser.hs
Normal file
29626
ghc-parser/src-7.8.3/Language/Haskell/GHC/HappyParser.hs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import Parser
|
||||
import SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import GHC.Hs
|
||||
|
||||
-- compiler/utils
|
||||
import OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import Lexer
|
||||
|
||||
import RdrHsSyn (runECP_P)
|
||||
|
||||
fullStatement :: P (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl GhcPs)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl GhcPs))
|
||||
fullDeclaration = fmap unitOL parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr GhcPs)
|
||||
fullExpression = runECP_P =<< parseExpression
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl GhcPs)))
|
||||
fullTypeSignature = fmap (noLoc . unitOL) parseTypeSignature
|
||||
|
||||
fullModule :: P (Located (HsModule GhcPs))
|
||||
fullModule = parseModule
|
@ -1,38 +0,0 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import Parser
|
||||
import SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import HsSyn
|
||||
|
||||
-- compiler/utils
|
||||
import OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import Lexer
|
||||
|
||||
fullStatement :: P (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl GhcPs)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl GhcPs))
|
||||
fullDeclaration = fmap unitOL parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr GhcPs)
|
||||
fullExpression = parseExpression
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl GhcPs)))
|
||||
fullTypeSignature = fmap (noLoc . unitOL) parseTypeSignature
|
||||
|
||||
fullModule :: P (Located (HsModule GhcPs))
|
||||
fullModule = parseModule
|
@ -1,40 +0,0 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import GHC.Parser
|
||||
import GHC.Types.SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import GHC.Hs
|
||||
|
||||
-- compiler/utils
|
||||
import GHC.Data.OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import GHC.Parser.Lexer
|
||||
|
||||
import GHC.Parser.PostProcess (runECP_P)
|
||||
|
||||
fullStatement :: P (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl GhcPs)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl GhcPs))
|
||||
fullDeclaration = fmap unitOL parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr GhcPs)
|
||||
fullExpression = runECP_P =<< parseExpression
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl GhcPs)))
|
||||
fullTypeSignature = fmap (noLoc . unitOL) parseTypeSignature
|
||||
|
||||
fullModule :: P (Located HsModule)
|
||||
fullModule = parseModule
|
@ -1,40 +0,0 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import GHC.Parser
|
||||
import GHC.Types.SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import GHC.Hs
|
||||
|
||||
-- compiler/utils
|
||||
import GHC.Data.OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import GHC.Parser.Lexer
|
||||
|
||||
import GHC.Parser.PostProcess (ECP(..), runPV)
|
||||
|
||||
fullStatement :: P (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl GhcPs)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl GhcPs))
|
||||
fullDeclaration = fmap unitOL parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr GhcPs)
|
||||
fullExpression = parseExpression >>= \p -> runPV $ unECP p
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl GhcPs)))
|
||||
fullTypeSignature = fmap (noLoc . unitOL) parseTypeSignature
|
||||
|
||||
fullModule :: P (Located HsModule)
|
||||
fullModule = parseModule
|
@ -1,40 +0,0 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import GHC.Parser
|
||||
import GHC.Types.SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import GHC.Hs
|
||||
|
||||
-- compiler/utils
|
||||
import GHC.Data.OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import GHC.Parser.Lexer
|
||||
|
||||
import GHC.Parser.PostProcess (ECP(..), runPV)
|
||||
|
||||
fullStatement :: P (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl GhcPs)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl GhcPs))
|
||||
fullDeclaration = fmap unitOL parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr GhcPs)
|
||||
fullExpression = parseExpression >>= \p -> runPV $ unECP p
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl GhcPs)))
|
||||
fullTypeSignature = fmap (noLoc . unitOL) parseTypeSignature
|
||||
|
||||
fullModule :: P (Located HsModule)
|
||||
fullModule = parseModule
|
@ -1,40 +0,0 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import GHC.Parser
|
||||
import GHC.Types.SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import GHC.Hs
|
||||
|
||||
-- compiler/utils
|
||||
import GHC.Data.OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import GHC.Parser.Lexer
|
||||
|
||||
import GHC.Parser.PostProcess (ECP(..), runPV)
|
||||
|
||||
fullStatement :: P (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl GhcPs)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl GhcPs))
|
||||
fullDeclaration = fmap unitOL parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr GhcPs)
|
||||
fullExpression = parseExpression >>= \p -> runPV $ unECP p
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl GhcPs)))
|
||||
fullTypeSignature = fmap (noLoc . unitOL) parseTypeSignature
|
||||
|
||||
fullModule :: P (Located (HsModule GhcPs))
|
||||
fullModule = parseModule
|
@ -1,40 +0,0 @@
|
||||
module Language.Haskell.GHC.HappyParser
|
||||
( fullStatement
|
||||
, fullImport
|
||||
, fullDeclaration
|
||||
, fullExpression
|
||||
, fullTypeSignature
|
||||
, fullModule
|
||||
) where
|
||||
|
||||
import GHC.Parser
|
||||
import GHC.Types.SrcLoc
|
||||
|
||||
-- compiler/hsSyn
|
||||
import GHC.Hs
|
||||
|
||||
-- compiler/utils
|
||||
import GHC.Data.OrdList
|
||||
|
||||
-- compiler/parser
|
||||
import GHC.Parser.Lexer
|
||||
|
||||
import GHC.Parser.PostProcess (ECP(..), runPV)
|
||||
|
||||
fullStatement :: P (Maybe (LStmt GhcPs (LHsExpr GhcPs)))
|
||||
fullStatement = parseStmt
|
||||
|
||||
fullImport :: P (LImportDecl GhcPs)
|
||||
fullImport = parseImport
|
||||
|
||||
fullDeclaration :: P (OrdList (LHsDecl GhcPs))
|
||||
fullDeclaration = fmap unitOL parseDeclaration
|
||||
|
||||
fullExpression :: P (LHsExpr GhcPs)
|
||||
fullExpression = parseExpression >>= \p -> runPV $ unECP p
|
||||
|
||||
fullTypeSignature :: P (Located (OrdList (LHsDecl GhcPs)))
|
||||
fullTypeSignature = fmap (noLoc . unitOL) parseTypeSignature
|
||||
|
||||
fullModule :: P (Located (HsModule GhcPs))
|
||||
fullModule = parseModule
|
36
hie.yaml
36
hie.yaml
@ -1,36 +0,0 @@
|
||||
cradle:
|
||||
cabal:
|
||||
- path: "./ghc-parser"
|
||||
component: "ghc-parser:lib:ghc-parser"
|
||||
- path: "./ipython-kernel"
|
||||
component: "ipython-kernel:lib:ipython-kernel"
|
||||
- path: "./src"
|
||||
component: "ihaskell:lib:ihaskell"
|
||||
- path: "./main"
|
||||
component: "ihaskell:exe:ihaskell"
|
||||
- path: "./test"
|
||||
component: "ihaskell:hspec"
|
||||
- path: "./ihaskell-display/ihaskell-aeson"
|
||||
component: "ihaskell-aeson:lib:ihaskell-aeson"
|
||||
- path: "./ihaskell-display/ihaskell-blaze"
|
||||
component: "ihaskell-blaze:lib:ihaskell-blaze"
|
||||
- path: "./ihaskell-display/ihaskell-charts"
|
||||
component: "ihaskell-charts:lib:ihaskell-charts"
|
||||
- path: "./ihaskell-display/ihaskell-diagrams"
|
||||
component: "ihaskell-diagrams:lib:ihaskell-diagrams"
|
||||
- path: "./ihaskell-display/ihaskell-gnuplot"
|
||||
component: "ihaskell-gnuplot:lib:ihaskell-gnuplot"
|
||||
- path: "./ihaskell-display/ihaskell-hatex"
|
||||
component: "ihaskell-hatex:lib:ihaskell-hatex"
|
||||
- path: "./ihaskell-display/ihaskell-juicypixels"
|
||||
component: "ihaskell-juicypixels:lib:ihaskell-juicypixels"
|
||||
- path: "./ihaskell-display/ihaskell-magic"
|
||||
component: "ihaskell-magic:lib:ihaskell-magic"
|
||||
- path: "./ihaskell-display/ihaskell-plot"
|
||||
component: "ihaskell-plot:lib:ihaskell-plot"
|
||||
- path: "./ihaskell-display/ihaskell-static-canvas"
|
||||
component: "ihaskell-static-canvas:lib:ihaskell-static-canvas"
|
||||
- path: "./ihaskell-display/ihaskell-widgets"
|
||||
component: "ihaskell-widgets:lib:ihaskell-widgets"
|
||||
- path: "./ihaskell-display/ihaskell-graphviz"
|
||||
component: "ihaskell-graphviz:lib:ihaskell-graphviz"
|
96
html/custom.css
Normal file
96
html/custom.css
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
Custom IHaskell CSS.
|
||||
*/
|
||||
|
||||
/* Styles used for the Hoogle display in the pager */
|
||||
.hoogle-doc {
|
||||
display: block;
|
||||
padding-bottom: 1.3em;
|
||||
padding-left: 0.4em;
|
||||
}
|
||||
.hoogle-code {
|
||||
display: block;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
}
|
||||
.hoogle-text {
|
||||
display: block;
|
||||
}
|
||||
.hoogle-name {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
.hoogle-head {
|
||||
font-weight: bold;
|
||||
}
|
||||
.hoogle-sub {
|
||||
display: block;
|
||||
margin-left: 0.4em;
|
||||
}
|
||||
.hoogle-package {
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
.hoogle-module {
|
||||
font-weight: bold;
|
||||
}
|
||||
.hoogle-class {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Styles used for basic displays */
|
||||
.get-type {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
display: block;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.show-type {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: monospace;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.err-msg {
|
||||
color: red;
|
||||
font-style: italic;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#unshowable {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.err-msg.in.collapse {
|
||||
padding-top: 0.7em;
|
||||
}
|
||||
|
||||
/* Code that will get highlighted before it is highlighted */
|
||||
.highlight-code {
|
||||
white-space: pre;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Hlint styles */
|
||||
.suggestion-warning {
|
||||
font-weight: bold;
|
||||
color: rgb(200, 130, 0);
|
||||
}
|
||||
.suggestion-error {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
.suggestion-name {
|
||||
font-weight: bold;
|
||||
}
|
@ -22,7 +22,7 @@ define(['require',
|
||||
var downArrow = 40;
|
||||
IPython.keyboard.keycodes.down = downArrow; // space
|
||||
|
||||
IPython.CodeCell.options_default['cm_config']['mode'] = 'ihaskell';
|
||||
IPython.CodeCell.options_default['cm_config']['mode'] = 'haskell';
|
||||
|
||||
utils.requireCodeMirrorMode('haskell', function(){
|
||||
// Create a multiplexing mode that uses Haskell highlighting by default but
|
||||
@ -52,6 +52,9 @@ define(['require',
|
||||
}
|
||||
});
|
||||
if(IPython.notebook.set_codemirror_mode){
|
||||
// this first one will not be necessary in the future
|
||||
// neither should the loop on all cells above
|
||||
IPython.notebook.set_codemirror_mode('null')
|
||||
IPython.notebook.set_codemirror_mode('ihaskell')
|
||||
}
|
||||
|
||||
|
BIN
html/logo-64x64.png
Normal file
BIN
html/logo-64x64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
viewBox="0 0 48.000001 47.999999"
|
||||
version="1.1"
|
||||
id="svg18"
|
||||
sodipodi:docname="haskell_logo.svg"
|
||||
inkscape:version="0.92.3 (unknown)">
|
||||
<metadata
|
||||
id="metadata22">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2495"
|
||||
inkscape:window-height="1416"
|
||||
id="namedview20"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:zoom="4.9870803"
|
||||
inkscape:cx="87.017073"
|
||||
inkscape:cy="4.4960944"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg18" />
|
||||
<defs
|
||||
id="defs5">
|
||||
<clipPath
|
||||
id="clip1">
|
||||
<path
|
||||
d="M 0,340.15625 H 481.89062 V 0 H 0 Z m 0,0"
|
||||
id="path2"
|
||||
inkscape:connector-curvature="0" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
id="surface0"
|
||||
transform="matrix(0.09960767,0,0,0.09960767,-0.1503886,5.8491832)">
|
||||
<g
|
||||
clip-path="url(#clip1)"
|
||||
id="g15"
|
||||
style="clip-rule:nonzero">
|
||||
<path
|
||||
style="fill:#453b61;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,340.15625 113.38672,170.07812 0,0 H 85.039062 L 198.42578,170.07812 85.039062,340.15625 Z m 0,0"
|
||||
id="path7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#5f5286;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 113.38672,340.15625 226.77344,170.07812 113.38672,0 h 85.03906 L 425.19531,340.15625 H 340.15625 L 269.29297,233.85937 198.42578,340.15625 Z m 0,0"
|
||||
id="path9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#8e508a;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 387.40234,240.94531 -37.79297,-56.6914 132.28125,-0.004 v 56.69531 z m 0,0"
|
||||
id="path11"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#8e508a;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 330.71094,155.90625 -37.79688,-56.691406 188.97656,-0.0039 v 56.695316 z m 0,0"
|
||||
id="path13"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.9 KiB |
@ -1,17 +1,17 @@
|
||||
{-# LANGUAGE TypeSynonymInstances #-}
|
||||
{-# LANGUAGE NoImplicitPrelude, TypeSynonymInstances, QuasiQuotes #-}
|
||||
|
||||
module IHaskell.Display.Aeson () where
|
||||
|
||||
import Data.Text as T
|
||||
import Data.ByteString.Lazy as LBS
|
||||
import Data.Text.Encoding as E
|
||||
|
||||
import ClassyPrelude
|
||||
import Data.Textual.Encoding
|
||||
import Data.Aeson
|
||||
import Data.Aeson.Encode.Pretty
|
||||
import Data.String.Here
|
||||
|
||||
import IHaskell.Display
|
||||
|
||||
instance IHaskellDisplay Value where
|
||||
display renderable = return $ Display [plain json]
|
||||
display renderable = return $ Display [plain json, html dom]
|
||||
where
|
||||
json = T.unpack $ E.decodeUtf8 $ LBS.toStrict $ encodePretty renderable
|
||||
json = unpack $ decodeUtf8 $ encodePretty renderable
|
||||
dom = [i|<div class="highlight-code" id="javascript">${json}</div>|]
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
@ -1,19 +1,19 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-aeson
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.3.0.1
|
||||
version: 0.2.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instances for Aeson
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
@ -27,41 +27,46 @@ license-file: LICENSE
|
||||
-- The package author(s).
|
||||
author: Andrew Gibiansky
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Aeson
|
||||
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
text,
|
||||
bytestring,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
here,
|
||||
classy-prelude >=0.7,
|
||||
aeson >= 0.7,
|
||||
aeson-pretty >= 0.7,
|
||||
chunked-data >=0.1,
|
||||
ihaskell >= 0.5
|
||||
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
19
ihaskell-display/ihaskell-basic/IHaskell/Display/Basic.hs
Normal file
19
ihaskell-display/ihaskell-basic/IHaskell/Display/Basic.hs
Normal file
@ -0,0 +1,19 @@
|
||||
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
|
||||
|
||||
module IHaskell.Display.Basic () where
|
||||
|
||||
import IHaskell.Display
|
||||
|
||||
import Text.Printf
|
||||
|
||||
instance Show a => IHaskellDisplay (Maybe a) where
|
||||
display just = return $ Display [stringDisplay, htmlDisplay]
|
||||
where
|
||||
stringDisplay = plain (show just)
|
||||
htmlDisplay = html str
|
||||
str =
|
||||
case just of
|
||||
Nothing -> "<span style='color: red; font-weight: bold;'>Nothing</span>"
|
||||
Just x -> printf
|
||||
"<span style='color: green; font-weight: bold;'>Just</span><span style='font-family: monospace;'>%s</span>"
|
||||
(show x)
|
4
ihaskell-display/ihaskell-basic/README.md
Normal file
4
ihaskell-display/ihaskell-basic/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
IHaskell-Display
|
||||
================
|
||||
|
||||
Instances of IHaskellDisplay for default prelude data types.
|
2
ihaskell-display/ihaskell-basic/Setup.hs
Normal file
2
ihaskell-display/ihaskell-basic/Setup.hs
Normal file
@ -0,0 +1,2 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,22 +1,25 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-graphviz
|
||||
-- Initial ihaskell-display.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The name of the package.
|
||||
name: ihaskell-basic
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
version: 0.2.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instance for GraphViz (external binary)
|
||||
synopsis: IHaskell display instances for basic types
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
homepage: http://www.github.com/gibiansky/IHaskell
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: MIT
|
||||
@ -25,44 +28,46 @@ license: MIT
|
||||
license-file: LICENSE
|
||||
|
||||
-- The package author(s).
|
||||
author: Lucas DiCioccio <lucas@dicioccio.fr>
|
||||
author: Andrew Gibiansky
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: Lucas DiCioccio <lucas@dicioccio.fr>,
|
||||
Vaibhav Sagar <vaibhavsagar@gmail.com>,
|
||||
Andrew Gibiansky <andrew.gibiansky@gmail.com>
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Graphviz
|
||||
|
||||
exposed-modules: IHaskell.Display.Basic
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
bytestring,
|
||||
text,
|
||||
process,
|
||||
ihaskell >= 0.6.2
|
||||
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
classy-prelude >=0.6,
|
||||
ihaskell >= 0.5
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
module IHaskell.Display.Blaze () where
|
||||
|
||||
import IHaskell.CSS (ihaskellCSS)
|
||||
import IHaskell.Display
|
||||
|
||||
import Text.Printf
|
||||
@ -16,4 +15,4 @@ instance IHaskellDisplay (MarkupM a) where
|
||||
where
|
||||
str = renderMarkup (void val)
|
||||
stringDisplay = plain str
|
||||
htmlDisplay = html' (Just ihaskellCSS) str
|
||||
htmlDisplay = html str
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
@ -1,22 +1,22 @@
|
||||
-- Initial ihaskell-display.cabal generated by cabal init. For further
|
||||
-- Initial ihaskell-display.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: ihaskell-blaze
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.3.0.1
|
||||
version: 0.2.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instances for blaze-html types
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
@ -30,40 +30,45 @@ license-file: LICENSE
|
||||
-- The package author(s).
|
||||
author: Andrew Gibiansky
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Blaze
|
||||
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
classy-prelude >=0.6,
|
||||
blaze-html >= 0.6,
|
||||
blaze-markup >= 0.5,
|
||||
ihaskell >= 0.5
|
||||
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
@ -1,15 +1,15 @@
|
||||
{-# LANGUAGE NoImplicitPrelude, CPP #-}
|
||||
|
||||
module IHaskell.Display.Charts () where
|
||||
|
||||
import ClassyPrelude
|
||||
|
||||
import System.Directory
|
||||
import Data.Default.Class
|
||||
import Graphics.Rendering.Chart.Renderable
|
||||
import Graphics.Rendering.Chart.Backend.Cairo
|
||||
import qualified Data.ByteString.Char8 as Char
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.Text.Encoding as T.Encoding
|
||||
import System.IO.Temp
|
||||
import System.IO.Unsafe
|
||||
import System.FilePath ((</>))
|
||||
|
||||
import IHaskell.Display
|
||||
|
||||
@ -31,22 +31,21 @@ instance IHaskellDisplay (Renderable a) where
|
||||
|
||||
chartData :: Renderable a -> FileFormat -> IO DisplayData
|
||||
chartData renderable format = do
|
||||
-- We should not have to round-trip this ByteString to a temp file.
|
||||
-- https://github.com/IHaskell/IHaskell/issues/1248
|
||||
withSystemTempDirectory "ihaskell-charts" $ \tmpdir -> do
|
||||
switchToTmpDir
|
||||
|
||||
-- Write the PNG image.
|
||||
let
|
||||
filename = tmpdir </> "ihaskell-chart.png"
|
||||
let filename = ".ihaskell-chart.png"
|
||||
opts = def { _fo_format = format, _fo_size = (width, height) }
|
||||
renderableToFile opts filename renderable
|
||||
mkFile opts filename renderable
|
||||
|
||||
-- Convert to base64.
|
||||
imgData <- readFile filename
|
||||
return $
|
||||
case format of
|
||||
PNG -> do
|
||||
-- Convert to base64.
|
||||
imgData <- Char.readFile filename
|
||||
pure $ png width height $ base64 imgData
|
||||
SVG -> do
|
||||
imgData <- BS.readFile filename
|
||||
pure $ svg $ T.Encoding.decodeUtf8 imgData
|
||||
_ -> error "Unreachable case, not PNG or SVG"
|
||||
PNG -> png width height $ base64 imgData
|
||||
SVG -> svg $ Char.unpack imgData
|
||||
#if MIN_VERSION_Chart_cairo(1,3,0)
|
||||
mkFile opts filename renderable = renderableToFile opts filename renderable
|
||||
#else
|
||||
mkFile opts filename renderable = renderableToFile opts renderable filename
|
||||
#endif
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,19 +1,19 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-charts
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.3.0.1
|
||||
version: 0.2.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instances for charts types
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
@ -27,46 +27,48 @@ license-file: LICENSE
|
||||
-- The package author(s).
|
||||
author: Andrew Gibiansky
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Charts
|
||||
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
classy-prelude >=0.10.5,
|
||||
bytestring,
|
||||
text,
|
||||
data-default-class,
|
||||
directory,
|
||||
filepath,
|
||||
temporary,
|
||||
Chart,
|
||||
Chart-cairo >=1.2,
|
||||
ihaskell >= 0.6.2
|
||||
|
||||
ihaskell >= 0.5
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,74 +1,53 @@
|
||||
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE NoImplicitPrelude, TypeSynonymInstances, FlexibleInstances #-}
|
||||
|
||||
module IHaskell.Display.Diagrams
|
||||
( diagram, animation
|
||||
, ManuallySized, withSizeSpec, withImgWidth, withImgHeight
|
||||
, ManuallySampled, withAnimFps
|
||||
) where
|
||||
module IHaskell.Display.Diagrams (diagram, animation) where
|
||||
|
||||
import ClassyPrelude
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Char8 as Char
|
||||
import qualified Data.Text.Encoding as T.Encoding
|
||||
import System.Directory
|
||||
import System.IO.Temp
|
||||
import System.FilePath ((</>))
|
||||
import Diagrams.Backend.Cairo
|
||||
import qualified Data.ByteString.Char8 as Char
|
||||
import System.IO.Unsafe
|
||||
|
||||
import Diagrams.Prelude
|
||||
import Diagrams.Backend.Cairo
|
||||
|
||||
import IHaskell.Display
|
||||
import IHaskell.Display.Diagrams.Animation
|
||||
import IHaskell.Display.Diagrams.ImgSize
|
||||
|
||||
instance IHaskellDisplay (ManuallySized (QDiagram Cairo V2 Double Any)) where
|
||||
instance IHaskellDisplay (QDiagram Cairo V2 Double Any) where
|
||||
display renderable = do
|
||||
png <- diagramData renderable PNG
|
||||
svg <- diagramData renderable SVG
|
||||
return $ Display [png, svg]
|
||||
|
||||
diagramData :: ManuallySized (Diagram Cairo) -> OutputType -> IO DisplayData
|
||||
diagramData (ManuallySized renderable imgWidth imgHeight) format = do
|
||||
-- We should not have to round-trip this ByteString to a temp file.
|
||||
-- https://github.com/IHaskell/IHaskell/issues/1248
|
||||
withSystemTempDirectory "ihaskell-diagram" $ \tmpdir -> do
|
||||
let path = case format of
|
||||
SVG -> tmpdir </> "ihaskell-diagram.svg"
|
||||
PNG -> tmpdir </> "ihaskell-diagram.png"
|
||||
_ -> error "Unreachable case"
|
||||
diagramData :: Diagram Cairo -> OutputType -> IO DisplayData
|
||||
diagramData renderable format = do
|
||||
switchToTmpDir
|
||||
|
||||
-- Write the image.
|
||||
renderCairo path (mkSizeSpec2D (Just imgWidth)
|
||||
(Just imgHeight)) renderable
|
||||
-- Compute width and height.
|
||||
let w = width renderable
|
||||
h = height renderable
|
||||
aspect = w / h
|
||||
imgHeight = 300
|
||||
imgWidth = aspect * imgHeight
|
||||
|
||||
case format of
|
||||
PNG -> do
|
||||
-- Convert to base64.
|
||||
imgData <- Char.readFile path
|
||||
pure $ png (floor imgWidth) (floor imgHeight) $ base64 imgData
|
||||
SVG -> do
|
||||
imgData <- BS.readFile path
|
||||
pure $ svg (T.Encoding.decodeUtf8 imgData)
|
||||
_ -> error "Unreachable case"
|
||||
-- Write the image.
|
||||
let filename = ".ihaskell-diagram." ++ extension format
|
||||
renderCairo filename (mkSizeSpec2D (Just imgWidth) (Just imgHeight)) renderable
|
||||
|
||||
-- Convert to base64.
|
||||
imgData <- readFile filename
|
||||
let value =
|
||||
case format of
|
||||
PNG -> png (floor imgWidth) (floor imgHeight) $ base64 imgData
|
||||
SVG -> svg $ Char.unpack imgData
|
||||
|
||||
return value
|
||||
|
||||
where
|
||||
extension SVG = "svg"
|
||||
extension PNG = "png"
|
||||
|
||||
-- Rendering hint.
|
||||
diagram :: Diagram Cairo -> Diagram Cairo
|
||||
diagram = id
|
||||
|
||||
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
|
||||
=> ManuallySizeable (QDiagram a v s m) where
|
||||
withSizeSpec spec renderable = ManuallySized renderable imgWidth imgHeight
|
||||
where
|
||||
aspect = width renderable / height renderable
|
||||
V2 imgWidth imgHeight = case getSpec spec of
|
||||
V2 (Just w) (Just h) -> V2 w h
|
||||
V2 (Just w) Nothing -> V2 w (w/aspect)
|
||||
V2 Nothing (Just h) -> V2 (aspect*h) h
|
||||
V2 Nothing Nothing -> (defaultDiagonal / sqrt (1 + aspect^2))
|
||||
*^ V2 aspect 1
|
||||
-- w^2 + h^2 = defaultDiagonal^2 / (1+aspect^2)
|
||||
-- * (aspect^2 + 1)
|
||||
-- = defaultDiagonal^2
|
||||
-- w/h = aspect/1 = aspect
|
||||
defaultDiagonal = 500
|
||||
|
||||
instance IHaskellDisplay (QDiagram Cairo V2 Double Any) where
|
||||
display = display . withSizeSpec (mkSizeSpec2D Nothing Nothing)
|
||||
|
@ -1,141 +1,55 @@
|
||||
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE DeriveFunctor, DeriveGeneric #-}
|
||||
{-# LANGUAGE NoImplicitPrelude, TypeSynonymInstances, FlexibleInstances #-}
|
||||
|
||||
module IHaskell.Display.Diagrams.Animation
|
||||
( animation
|
||||
, ManuallySampled, withAnimFps
|
||||
) where
|
||||
module IHaskell.Display.Diagrams.Animation (animation) where
|
||||
|
||||
import qualified Data.ByteString.Char8 as CBS
|
||||
import qualified Data.Text as T
|
||||
import ClassyPrelude hiding (filename)
|
||||
|
||||
import GHC.Generics (Generic)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Diagrams.Prelude
|
||||
import Diagrams.Backend.Cairo
|
||||
import Diagrams.Backend.Cairo.CmdLine (GifOpts(..))
|
||||
import Diagrams.Backend.CmdLine (DiagramOpts(..), mainRender)
|
||||
import System.IO.Temp
|
||||
import System.FilePath ((</>))
|
||||
|
||||
import IHaskell.Display
|
||||
import IHaskell.Display.Diagrams.ImgSize
|
||||
|
||||
|
||||
data ManuallySampled a = ManuallySampled
|
||||
{ contentToSample :: a
|
||||
, signalManualSampleRate :: Maybe Rational
|
||||
} deriving (Show, Functor, Generic)
|
||||
|
||||
class ManuallySamplable a where
|
||||
withSamplingSpec :: Maybe Rational -> a -> ManuallySampled a
|
||||
|
||||
|
||||
defaultFps = 30
|
||||
|
||||
withAnimFps :: ManuallySamplable a => Rational -> a -> ManuallySampled a
|
||||
withAnimFps fps = withSamplingSpec (Just fps)
|
||||
|
||||
|
||||
instance IHaskellDisplay (ManuallySized (ManuallySampled (QAnimation Cairo V2 Double Any))) where
|
||||
instance IHaskellDisplay (QAnimation Cairo V2 Double Any) where
|
||||
display renderable = do
|
||||
gif <- animationData renderable
|
||||
return $ Display [html' Nothing $ "<img src=\"data:image/gif;base64," ++ gif ++ "\" />"]
|
||||
return $ Display [html $ "<img src=\"data:image/gif;base64,"
|
||||
++ gif ++ "\" />"]
|
||||
|
||||
animationData :: Animation Cairo V2 Double -> IO String
|
||||
animationData renderable = do
|
||||
switchToTmpDir
|
||||
|
||||
animationData :: ManuallySized (ManuallySampled (Animation Cairo V2 Double)) -> IO String
|
||||
animationData (ManuallySized (ManuallySampled renderable fps) imgWidth imgHeight) = do
|
||||
-- We should not have to round-trip this ByteString to a temp file.
|
||||
-- https://github.com/IHaskell/IHaskell/issues/1248
|
||||
withSystemTempDirectory "ihaskell-diagram" $ \tmpdir -> do
|
||||
-- Generate the frames
|
||||
let fps = 30
|
||||
animAdjusted = animEnvelope' fps renderable
|
||||
frames = simulate fps animAdjusted
|
||||
timediff = 100 `div` ceiling fps :: Int
|
||||
frameSet = map (\x -> (x # bg white, timediff)) frames
|
||||
|
||||
let path = tmpdir </> "ihaskell-diagram.gif"
|
||||
-- Compute width and height.
|
||||
let shape = activeStart animAdjusted
|
||||
w = width shape
|
||||
h = height shape
|
||||
aspect = w / h
|
||||
imgHeight = 300
|
||||
imgWidth = aspect * imgHeight
|
||||
|
||||
-- Generate the frames
|
||||
let actualFps = fromMaybe defaultFps fps
|
||||
animAdjusted = animEnvelope' actualFps renderable
|
||||
frames = simulate actualFps animAdjusted
|
||||
timediff = 100 `div` ceiling actualFps :: Int
|
||||
frameSet = map (\x -> (x # bg white, timediff)) frames
|
||||
|
||||
-- Write the image.
|
||||
let diagOpts = DiagramOpts
|
||||
{ _width = Just . ceiling $ imgWidth
|
||||
, _height = Just . ceiling $ imgHeight
|
||||
, _output = path
|
||||
}
|
||||
gifOpts = GifOpts { _dither = True, _noLooping = False, _loopRepeat = Nothing }
|
||||
mainRender (diagOpts, gifOpts) frameSet
|
||||
|
||||
-- Convert to ascii represented base64 encoding
|
||||
imgData <- CBS.readFile path
|
||||
return . T.unpack . base64 $ imgData
|
||||
-- Write the image.
|
||||
let filename = ".ihaskell-diagram.gif"
|
||||
diagOpts = DiagramOpts
|
||||
{ _width = Just . ceiling $ imgWidth
|
||||
, _height = Just . ceiling $ imgHeight
|
||||
, _output = filename
|
||||
}
|
||||
gifOpts = GifOpts { _dither = True, _noLooping = False, _loopRepeat = Nothing }
|
||||
mainRender (diagOpts, gifOpts) frameSet
|
||||
|
||||
-- Convert to ascii represented base64 encoding
|
||||
imgData <- readFile filename
|
||||
return . unpack . base64 $ imgData
|
||||
|
||||
-- Rendering hint.
|
||||
animation :: Animation Cairo V2 Double -> Animation Cairo V2 Double
|
||||
animation = id
|
||||
|
||||
|
||||
getImgSize renderable sizeSpec fps = out
|
||||
where
|
||||
actualFps = fromMaybe defaultFps fps
|
||||
shape = activeStart $ animEnvelope' actualFps renderable
|
||||
aspect = width shape / height shape
|
||||
out = case getSpec sizeSpec of
|
||||
V2 (Just w) (Just h) -> V2 w h
|
||||
V2 (Just w) Nothing -> V2 w (w/aspect)
|
||||
V2 Nothing (Just h) -> V2 (aspect*h) h
|
||||
V2 Nothing Nothing -> (defaultDiagonal / sqrt (1 + aspect^2))
|
||||
*^ V2 aspect 1
|
||||
-- w^2 + h^2 = defaultDiagonal^2 / (1+aspect^2)
|
||||
-- * (aspect^2 + 1)
|
||||
-- = defaultDiagonal^2
|
||||
-- w/h = aspect/1 = aspect
|
||||
defaultDiagonal = 500
|
||||
|
||||
|
||||
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
|
||||
=> ManuallySamplable (QAnimation b v s m) where
|
||||
withSamplingSpec fps renderable = ManuallySampled renderable fps
|
||||
|
||||
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
|
||||
=> ManuallySamplable (ManuallySized (QAnimation b v s m)) where
|
||||
withSamplingSpec fps sizedRenderable = ManuallySampled sizedRenderable fps
|
||||
|
||||
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
|
||||
=> ManuallySizeable (QAnimation b v s m) where
|
||||
withSizeSpec spec renderable = ManuallySized renderable imgWidth imgHeight
|
||||
where
|
||||
fps = Nothing
|
||||
V2 imgWidth imgHeight = getImgSize renderable spec fps
|
||||
|
||||
instance (b ~ Cairo, v ~ V2, s ~ Double, m ~ Any)
|
||||
=> ManuallySizeable (ManuallySampled (QAnimation b v s m)) where
|
||||
withSizeSpec spec (ManuallySampled renderable fps) = out
|
||||
where
|
||||
out = ManuallySized (ManuallySampled renderable fps) w h
|
||||
V2 w h = getImgSize renderable spec fps
|
||||
|
||||
|
||||
instance IHaskellDisplay (QAnimation Cairo V2 Double Any) where
|
||||
display = display . withSizeSpec (mkSizeSpec2D Nothing Nothing) . withSamplingSpec fps
|
||||
where
|
||||
fps = Nothing
|
||||
|
||||
instance IHaskellDisplay (ManuallySized (QAnimation Cairo V2 Double Any)) where
|
||||
display (ManuallySized renderable w h) = out
|
||||
where
|
||||
fps = Nothing
|
||||
sizeSpec = mkSizeSpec2D (Just w) (Just h)
|
||||
out = display . withSizeSpec sizeSpec $ withSamplingSpec fps renderable
|
||||
|
||||
instance IHaskellDisplay (ManuallySampled (QAnimation Cairo V2 Double Any)) where
|
||||
display = display . withSizeSpec (mkSizeSpec2D Nothing Nothing)
|
||||
|
||||
instance IHaskellDisplay (ManuallySampled (ManuallySized (QAnimation Cairo V2 Double Any))) where
|
||||
display (ManuallySampled (ManuallySized renderable w h) fps) = out
|
||||
where
|
||||
sizeSpec = mkSizeSpec2D (Just w) (Just h)
|
||||
out = display . withSizeSpec sizeSpec $ withSamplingSpec fps renderable
|
||||
|
@ -1,24 +0,0 @@
|
||||
{-# LANGUAGE DeriveFunctor, DeriveGeneric #-}
|
||||
|
||||
module IHaskell.Display.Diagrams.ImgSize where
|
||||
|
||||
import GHC.Generics (Generic)
|
||||
import Diagrams.Prelude (SizeSpec, mkSizeSpec2D, V2)
|
||||
|
||||
data ManuallySized a = ManuallySized
|
||||
{ contentToDisplay :: a
|
||||
, imgManualWidth :: Double
|
||||
, imgManualHeight :: Double
|
||||
} deriving (Show, Functor, Generic)
|
||||
|
||||
class ManuallySizeable a where
|
||||
withSizeSpec :: SizeSpec V2 Double -> a -> ManuallySized a
|
||||
|
||||
withImgWidth :: ManuallySizeable a => Int -> a -> ManuallySized a
|
||||
withImgWidth imgWidth = withSizeSpec $ mkSizeSpec2D (Just $ fromIntegral imgWidth)
|
||||
Nothing
|
||||
|
||||
withImgHeight :: ManuallySizeable a => Int -> a -> ManuallySized a
|
||||
withImgHeight imgHeight = withSizeSpec $ mkSizeSpec2D Nothing
|
||||
(Just $ fromIntegral imgHeight)
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
331
ihaskell-display/ihaskell-diagrams/Test.ipynb
Normal file
331
ihaskell-display/ihaskell-diagrams/Test.ipynb
Normal file
File diff suppressed because one or more lines are too long
@ -1,19 +1,19 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-diagrams
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.4.0.0
|
||||
version: 0.2.1.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instances for diagram types
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
@ -27,51 +27,52 @@ license-file: LICENSE
|
||||
-- The package author(s).
|
||||
author: Andrew Gibiansky
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Diagrams
|
||||
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
other-modules: IHaskell.Display.Diagrams.Animation
|
||||
IHaskell.Display.Diagrams.ImgSize
|
||||
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
text,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
classy-prelude >=0.10.5,
|
||||
bytestring,
|
||||
directory,
|
||||
temporary,
|
||||
filepath,
|
||||
-- Use diagrams wrapper package to ensure all same versions of subpackages
|
||||
diagrams >= 1.3,
|
||||
diagrams-lib,
|
||||
diagrams-cairo,
|
||||
ihaskell >= 0.11,
|
||||
ihaskell >= 0.5,
|
||||
|
||||
-- The active package, used to represent animations
|
||||
active >= 0.2
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,79 +0,0 @@
|
||||
{-
|
||||
(This paragraph was made obsolete by PR #1362 which unified the 3 types
|
||||
of plot. But it's still useful commentary.)
|
||||
There are 3 types of plots to consider in haskell-gnuplot: Plot, Frame and Multiplot.
|
||||
Plot types are the actual plots, whereas Frame types are plots with additional options
|
||||
e.g. custom axes tics, graph title etc.. Multiplots are collections of 2D and/or 3D plots.
|
||||
We have to create instances of IHaskellDisplay for all of these types.
|
||||
|
||||
Note: To stop gnuplot from printing the filepath ontop of the canvas, you have to set
|
||||
the gnuplot option "key" to "noautotitle".
|
||||
Code: Graphics.Gnuplot.Frame.cons (Graphics.Gnuplot.Frame.OptionSet.add
|
||||
(Graphics.Gnuplot.Frame.Option.key "")
|
||||
["noautotitle"] $ ...)
|
||||
-}
|
||||
module IHaskell.Display.Gnuplot where
|
||||
|
||||
import qualified Graphics.Gnuplot.Plot as P
|
||||
import qualified Graphics.Gnuplot.Frame as F
|
||||
import qualified Graphics.Gnuplot.MultiPlot as M
|
||||
import qualified Graphics.Gnuplot.Terminal.PNG as Pn
|
||||
import qualified Graphics.Gnuplot.Terminal.SVG as Sv
|
||||
import qualified Graphics.Gnuplot.Display as D
|
||||
import qualified Graphics.Gnuplot.Graph as G
|
||||
import qualified Data.ByteString.Char8 as Char
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.Text.Encoding as T.Encoding
|
||||
import System.IO.Temp
|
||||
import System.FilePath ((</>))
|
||||
import Graphics.Gnuplot.Advanced (plot)
|
||||
import IHaskell.Display
|
||||
|
||||
-- Plot-types
|
||||
instance G.C graph => IHaskellDisplay (P.T graph) where
|
||||
display = graphDataDisplayBoth
|
||||
|
||||
-- Frame-types
|
||||
instance G.C graph => IHaskellDisplay (F.T graph) where
|
||||
display = graphDataDisplayBoth
|
||||
|
||||
-- Type: Multiplot
|
||||
instance IHaskellDisplay M.T where
|
||||
display = graphDataDisplayBoth
|
||||
|
||||
-- Width and height
|
||||
w = 300
|
||||
|
||||
h = 300
|
||||
|
||||
graphDataPNG :: D.C gfx => gfx -> IO DisplayData
|
||||
graphDataPNG graph = do
|
||||
-- We should not have to round-trip this ByteString to a temp file.
|
||||
-- https://github.com/IHaskell/IHaskell/issues/1248
|
||||
withSystemTempDirectory "ihaskell-gnuplot" $ \tmpdir -> do
|
||||
let path = tmpdir </> "ihaskell-gnuplot.png"
|
||||
|
||||
-- Write the image.
|
||||
plot (Pn.cons path) graph
|
||||
|
||||
-- Read back, and convert to base64.
|
||||
imgData <- Char.readFile path
|
||||
return $ png w h $ base64 imgData
|
||||
|
||||
graphDataSVG :: D.C gfx => gfx -> IO DisplayData
|
||||
graphDataSVG graph = do
|
||||
withSystemTempDirectory "ihaskell-gnuplot" $ \tmpdir -> do
|
||||
let path = tmpdir </> "ihaskell-gnuplot.svg"
|
||||
|
||||
-- Write the image.
|
||||
plot (Sv.cons path) graph
|
||||
|
||||
-- Read back
|
||||
imgData <- BS.readFile path
|
||||
return $ svg $ T.Encoding.decodeUtf8 imgData
|
||||
|
||||
graphDataDisplayBoth :: D.C gfx => gfx -> IO Display
|
||||
graphDataDisplayBoth fig = do
|
||||
pngDisp <- graphDataPNG fig
|
||||
svgDisp <- graphDataSVG fig
|
||||
return $ Display [pngDisp, svgDisp]
|
@ -1,3 +0,0 @@
|
||||
import Distribution.Simple
|
||||
|
||||
main = defaultMain
|
@ -1,118 +0,0 @@
|
||||
|
||||
-- | A module to help displaying information using the amazing Graphviz
|
||||
-- (https://www.graphviz.org/) graph layouts.
|
||||
--
|
||||
-- You need to install and have graphviz tools available in your environment.
|
||||
--
|
||||
-- Currently only 'dot' is provided as a proof-of-concept. This module may be
|
||||
-- split in two (a package as an helper to Graphviz command line and this
|
||||
-- package to provide 'IHaskellDisplay' instances.
|
||||
--
|
||||
-- Minimal notebook example:
|
||||
--
|
||||
-- @ import IHaskell.Display.Graphviz @
|
||||
-- @ dot "digraph { l -> o; o -> v; v -> e; h -> a ; a -> s; s -> k ; k -> e ; e -> l ; l -> l}" @
|
||||
module IHaskell.Display.Graphviz (
|
||||
dot
|
||||
, neato
|
||||
, fdp
|
||||
, sfdp
|
||||
, circo
|
||||
, twopi
|
||||
, nop
|
||||
, nop2
|
||||
, osage
|
||||
, patchwork
|
||||
, Graphviz(..)
|
||||
) where
|
||||
|
||||
import System.Process (readProcess)
|
||||
import qualified Data.Text as T
|
||||
import IHaskell.Display
|
||||
|
||||
-- | The body of a Graphviz program.
|
||||
--
|
||||
-- e.g. @ graph { a -- b } @
|
||||
type GraphvizProgramBody = String
|
||||
|
||||
-- | Main Graphviz object.
|
||||
data Graphviz
|
||||
= Dot !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Dot](https://graphviz.org/docs/layouts/dot/)
|
||||
| Neato !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Neato](https://graphviz.org/docs/layouts/neato/)
|
||||
| Fdp !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Fdp](https://graphviz.org/docs/layouts/fdp/)
|
||||
| Sfdp !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Sfdp](https://graphviz.org/docs/layouts/sfdp/)
|
||||
| Circo !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Circo](https://graphviz.org/docs/layouts/circo/)
|
||||
| Twopi !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Twopi](https://graphviz.org/docs/layouts/twopi/)
|
||||
| Nop !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Nop](https://graphviz.org/docs/layouts/nop/)
|
||||
| Nop2 !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Nop2](https://graphviz.org/docs/layouts/nop2/)
|
||||
| Osage !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Osage](https://graphviz.org/docs/layouts/osage/)
|
||||
| Patchwork !GraphvizProgramBody
|
||||
-- ^ A Graphviz plotted using [Patchwork](https://graphviz.org/docs/layouts/patchwork/)
|
||||
|
||||
|
||||
-- | Create a 'Graphviz' using 'dot'.
|
||||
dot :: GraphvizProgramBody -> Graphviz
|
||||
dot = Dot
|
||||
|
||||
-- | Create a 'Graphviz' using 'neato'.
|
||||
neato :: GraphvizProgramBody -> Graphviz
|
||||
neato = Neato
|
||||
|
||||
-- | Create a 'Graphviz' using 'fdp'.
|
||||
fdp :: GraphvizProgramBody -> Graphviz
|
||||
fdp = Fdp
|
||||
|
||||
-- | Create a 'Graphviz' using 'sfdp'.
|
||||
sfdp :: GraphvizProgramBody -> Graphviz
|
||||
sfdp = Sfdp
|
||||
|
||||
-- | Create a 'Graphviz' using 'circo'.
|
||||
circo :: GraphvizProgramBody -> Graphviz
|
||||
circo = Circo
|
||||
|
||||
-- | Create a 'Graphviz' using 'twopi'.
|
||||
twopi :: GraphvizProgramBody -> Graphviz
|
||||
twopi = Twopi
|
||||
|
||||
-- | Create a 'Graphviz' using 'nop'.
|
||||
nop :: GraphvizProgramBody -> Graphviz
|
||||
nop = Nop
|
||||
|
||||
-- | Create a 'Graphviz' using 'nop2'.
|
||||
nop2 :: GraphvizProgramBody -> Graphviz
|
||||
nop2 = Nop2
|
||||
|
||||
-- | Create a 'Graphviz' using 'osage'.
|
||||
osage :: GraphvizProgramBody -> Graphviz
|
||||
osage = Osage
|
||||
|
||||
-- | Create a 'Graphviz' using 'patchwork'.
|
||||
patchwork :: GraphvizProgramBody -> Graphviz
|
||||
patchwork = Patchwork
|
||||
|
||||
instance IHaskellDisplay Graphviz where
|
||||
display fig = do
|
||||
svgDisp <- graphDataSVG fig
|
||||
return $ Display [svgDisp]
|
||||
|
||||
graphDataSVG :: Graphviz -> IO DisplayData
|
||||
graphDataSVG prog = svg . T.pack <$> case prog of
|
||||
Dot dotBody -> readProcess "dot" ["-Tsvg"] dotBody
|
||||
Neato dotBody -> readProcess "neato" ["-Tsvg"] dotBody
|
||||
Fdp dotBody -> readProcess "fdp" ["-Tsvg"] dotBody
|
||||
Sfdp dotBody -> readProcess "sfdp" ["-Tsvg"] dotBody
|
||||
Circo dotBody -> readProcess "circo" ["-Tsvg"] dotBody
|
||||
Twopi dotBody -> readProcess "twopi" ["-Tsvg"] dotBody
|
||||
Nop dotBody -> readProcess "nop" ["-Tsvg"] dotBody
|
||||
Nop2 dotBody -> readProcess "nop2" ["-Tsvg"] dotBody
|
||||
Osage dotBody -> readProcess "osage" ["-Tsvg"] dotBody
|
||||
Patchwork dotBody -> readProcess "patchwork" ["-Tsvg"] dotBody
|
@ -1,3 +0,0 @@
|
||||
import Distribution.Simple
|
||||
|
||||
main = defaultMain
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
@ -1,7 +1,7 @@
|
||||
name: ihaskell-hatex
|
||||
version: 0.2.1.1
|
||||
version: 0.2.0.0
|
||||
synopsis: IHaskell display instances for hatex
|
||||
-- description:
|
||||
-- description:
|
||||
homepage: http://www.github.com/gibiansky/IHaskell
|
||||
license: MIT
|
||||
license-file: LICENSE
|
||||
@ -9,14 +9,14 @@ author: Adam Vogt
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
category: Development
|
||||
build-type: Simple
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
library
|
||||
exposed-modules: IHaskell.Display.Hatex
|
||||
build-depends: base >=4.9 && <5,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
text,
|
||||
HaTeX >= 3.9,
|
||||
ihaskell >= 0.5
|
||||
default-language: Haskell2010
|
||||
|
||||
|
||||
|
@ -1,36 +1,94 @@
|
||||
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
|
||||
{-# LANGUAGE NoImplicitPrelude, TypeSynonymInstances, FlexibleInstances #-}
|
||||
|
||||
module IHaskell.Display.Juicypixels (module IHaskell.Display, module Codec.Picture) where
|
||||
|
||||
import qualified Codec.Picture as P
|
||||
import Codec.Picture (Image(..))
|
||||
import Codec.Picture.Png (PngSavable, encodePng)
|
||||
import IHaskell.Display (IHaskellDisplay, Display(..), display, png, base64)
|
||||
import Data.ByteString.Lazy (ByteString, toStrict)
|
||||
import Codec.Picture
|
||||
import ClassyPrelude
|
||||
import IHaskell.Display
|
||||
import System.Directory
|
||||
import System.IO.Unsafe
|
||||
|
||||
instance IHaskellDisplay (Image P.Pixel8) where
|
||||
display = return . format
|
||||
-- instances
|
||||
instance IHaskellDisplay DynamicImage where
|
||||
display = displayImageAsJpg
|
||||
|
||||
instance IHaskellDisplay (Image P.Pixel16) where
|
||||
display = return . format
|
||||
instance IHaskellDisplay (Image Pixel8) where
|
||||
display = displayImageAsJpg . ImageY8
|
||||
|
||||
instance IHaskellDisplay (Image P.PixelYA8) where
|
||||
display = return . format
|
||||
instance IHaskellDisplay (Image Pixel16) where
|
||||
display = displayImageAsJpg . ImageY16
|
||||
|
||||
instance IHaskellDisplay (Image P.PixelYA16) where
|
||||
display = return . format
|
||||
instance IHaskellDisplay (Image PixelF) where
|
||||
display = displayImageAsJpg . ImageYF
|
||||
|
||||
instance IHaskellDisplay (Image P.PixelRGB8) where
|
||||
display = return . format
|
||||
instance IHaskellDisplay (Image PixelYA8) where
|
||||
display = displayImageAsJpg . ImageYA8
|
||||
|
||||
instance IHaskellDisplay (Image P.PixelRGB16) where
|
||||
display = return . format
|
||||
instance IHaskellDisplay (Image PixelYA16) where
|
||||
display = displayImageAsJpg . ImageYA16
|
||||
|
||||
instance IHaskellDisplay (Image P.PixelRGBA8) where
|
||||
display = return . format
|
||||
instance IHaskellDisplay (Image PixelRGB8) where
|
||||
display = displayImageAsJpg . ImageRGB8
|
||||
|
||||
instance IHaskellDisplay (Image P.PixelRGBA16) where
|
||||
display = return . format
|
||||
instance IHaskellDisplay (Image PixelRGB16) where
|
||||
display = displayImageAsJpg . ImageRGB16
|
||||
|
||||
format :: PngSavable a => Image a -> Display
|
||||
format im@(Image w h _) = Display [png w h . base64 . toStrict . encodePng $ im]
|
||||
instance IHaskellDisplay (Image PixelRGBF) where
|
||||
display = displayImageAsJpg . ImageRGBF
|
||||
|
||||
instance IHaskellDisplay (Image PixelRGBA8) where
|
||||
display = displayImageAsJpg . ImageRGBA8
|
||||
|
||||
instance IHaskellDisplay (Image PixelRGBA16) where
|
||||
display = displayImageAsJpg . ImageRGBA16
|
||||
|
||||
instance IHaskellDisplay (Image PixelYCbCr8) where
|
||||
display = displayImageAsJpg . ImageYCbCr8
|
||||
|
||||
instance IHaskellDisplay (Image PixelCMYK8) where
|
||||
display = displayImageAsJpg . ImageCMYK8
|
||||
|
||||
instance IHaskellDisplay (Image PixelCMYK16) where
|
||||
display = displayImageAsJpg . ImageCMYK16
|
||||
|
||||
-- main rendering function
|
||||
displayImageAsJpg :: DynamicImage -> IO Display
|
||||
displayImageAsJpg renderable = do
|
||||
switchToTmpDir
|
||||
|
||||
let filename = ".ihaskell.juicypixels.jpg"
|
||||
-- Write the image
|
||||
saveJpgImage 95 filename renderable
|
||||
-- Convert to base64.
|
||||
imgData <- readFile filename
|
||||
return $ Display [jpg (imWidth renderable) (imHeight renderable) $ base64 imgData]
|
||||
|
||||
-- The type DynamicImage does not have a function to extract width and height
|
||||
imWidth :: DynamicImage -> Int
|
||||
imWidth img = w
|
||||
where
|
||||
(w, h) = imWidthHeight img
|
||||
|
||||
imHeight :: DynamicImage -> Int
|
||||
imHeight img = h
|
||||
where
|
||||
(w, h) = imWidthHeight img
|
||||
|
||||
-- Helper functions to pattern match on the DynamicImage Constructors
|
||||
imWidthHeight :: DynamicImage -> (Int, Int)
|
||||
imWidthHeight (ImageY8 im) = imWH im
|
||||
imWidthHeight (ImageY16 im) = imWH im
|
||||
imWidthHeight (ImageYF im) = imWH im
|
||||
imWidthHeight (ImageYA8 im) = imWH im
|
||||
imWidthHeight (ImageYA16 im) = imWH im
|
||||
imWidthHeight (ImageRGB8 im) = imWH im
|
||||
imWidthHeight (ImageRGB16 im) = imWH im
|
||||
imWidthHeight (ImageRGBF im) = imWH im
|
||||
imWidthHeight (ImageRGBA8 im) = imWH im
|
||||
imWidthHeight (ImageRGBA16 im) = imWH im
|
||||
imWidthHeight (ImageYCbCr8 im) = imWH im
|
||||
imWidthHeight (ImageCMYK8 im) = imWH im
|
||||
imWidthHeight (ImageCMYK16 im) = imWH im
|
||||
|
||||
imWH :: (Image a) -> (Int, Int)
|
||||
imWH im = (imageWidth im, imageHeight im)
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
@ -1,23 +1,23 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-juicypixels
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 1.1.0.1
|
||||
version: 0.2.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell - IHaskellDisplay instances of the image types of the JuicyPixels package.
|
||||
|
||||
-- A longer description of the package.
|
||||
description: IHaskellDisplay instances of the image types of the JuicyPixels package. They are displayed as .JPG images.
|
||||
DynamicImages and Images of types PixelRGBA16, PixelRGBA8, PixelRGB16, PixelRGB8,
|
||||
DynamicImages and Images of types PixelRGBA16, PixelRGBA8, PixelRGB16, PixelRGB8,
|
||||
PixelYA16, PixelYA8, Pixel16, Pixel8, PixelCMYK16, PixelCMYK8, PixelF, Pixel32
|
||||
are supported.
|
||||
The module IHaskell.Juicypixels re-exports the modules IHaskell.Display and Codec.Picture.
|
||||
are supported.
|
||||
The module IHaskell.Juicypixels re-exports the modules IHaskell.Display and Codec.Picture.
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
@ -29,45 +29,48 @@ license: MIT
|
||||
license-file: LICENSE
|
||||
|
||||
-- The package author(s).
|
||||
author: Roland Senn,
|
||||
Will Yager
|
||||
author: Roland Senn
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: rsx@bluewin.ch,
|
||||
will.yager@gmail.com
|
||||
maintainer: rsx@bluewin.ch
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Juicypixels
|
||||
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
classy-prelude >=0.10.5,
|
||||
bytestring,
|
||||
directory,
|
||||
JuicyPixels >= 3.1.3,
|
||||
ihaskell >= 0.6.2
|
||||
|
||||
ihaskell >= 0.5
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
@ -1,57 +1,42 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"hidden": false
|
||||
},
|
||||
"source": [
|
||||
"# Notebook test\n",
|
||||
"\n",
|
||||
"This IHaskell noteook should just test, whether IHaskell and JuicyPixels are properly installed and working.\n",
|
||||
"\n",
|
||||
"Just click in the box below and click on the \"Run\" command in the above menu. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"hidden": false,
|
||||
"jupyter": {
|
||||
"outputs_hidden": false
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}\n",
|
||||
"\n",
|
||||
"import IHaskell.Display.Juicypixels\n",
|
||||
"import Codec.Picture\n",
|
||||
" \n",
|
||||
"myImage = generateImage pixelRenderer 250 300\n",
|
||||
" where pixelRenderer x y = PixelRGB8 (fromIntegral x) (fromIntegral y) 128\n",
|
||||
" \n",
|
||||
"myImage "
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Haskell",
|
||||
"language": "haskell",
|
||||
"name": "haskell"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "ihaskell",
|
||||
"file_extension": ".hs",
|
||||
"mimetype": "text/x-haskell",
|
||||
"name": "haskell",
|
||||
"pygments_lexer": "Haskell",
|
||||
"version": "8.10.4"
|
||||
}
|
||||
"language": "haskell",
|
||||
"name": "",
|
||||
"signature": "sha256:b9b36c162e37a16b252cd1f06e4c2991e0a80710e7fc184be82dd6b18e6dcf01"
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
"nbformat": 3,
|
||||
"nbformat_minor": 0,
|
||||
"worksheets": [
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"{-# LANGUAGE NoImplicitPrelude, TypeSynonymInstances, FlexibleInstances #-}\n",
|
||||
"\n",
|
||||
"import IHaskell.Display.Juicypixels\n",
|
||||
" \n",
|
||||
"myImage = generateImage pixelRenderer 250 300\n",
|
||||
" where pixelRenderer x y = PixelRGB8 (fromIntegral x) (fromIntegral y) 128\n",
|
||||
" \n",
|
||||
"myImage "
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"prompt_number": 8
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": []
|
||||
}
|
||||
],
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
}
|
@ -2,23 +2,21 @@
|
||||
|
||||
module IHaskell.Display.Magic () where
|
||||
|
||||
import IHaskell.Display
|
||||
import Magic
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Data.ByteString.Unsafe as B
|
||||
import qualified Data.ByteString.Base64 as Base64
|
||||
import qualified Data.ByteString.Char8 as Char
|
||||
import Data.ByteString.UTF8
|
||||
import qualified Data.ByteString.UTF8 as B
|
||||
import qualified Data.ByteString.Unsafe as B
|
||||
|
||||
import Text.Read
|
||||
import Data.Char
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as T
|
||||
import Text.Read
|
||||
|
||||
import Magic
|
||||
|
||||
import IHaskell.CSS (ihaskellCSS)
|
||||
import IHaskell.Display
|
||||
import IHaskell.IPython.Types (MimeType(MimeSvg))
|
||||
|
||||
import Data.ByteString.UTF8
|
||||
|
||||
instance IHaskellDisplay T.Text where
|
||||
display = display . T.encodeUtf8
|
||||
@ -37,7 +35,7 @@ withClass :: MagicClass -> B.ByteString -> DisplayData
|
||||
withClass SVG = DisplayData MimeSvg . T.decodeUtf8
|
||||
withClass (PNG w h) = png w h . T.decodeUtf8 . Base64.encode
|
||||
withClass JPG = jpg 400 300 . T.decodeUtf8 . Base64.encode
|
||||
withClass HTML = html' (Just ihaskellCSS) . B.toString
|
||||
withClass HTML = html . B.toString
|
||||
withClass LaTeX = latex . B.toString
|
||||
withClass _ = plain . B.toString
|
||||
|
||||
|
@ -10,14 +10,6 @@ cd ihaskell-magic
|
||||
cabal install
|
||||
```
|
||||
|
||||
On OSX:
|
||||
|
||||
```bash
|
||||
brew install libmagic
|
||||
brew link libmagic
|
||||
stack install ihaskell-magic --extra-lib-dirs=/usr/local/lib --extra-include-dirs=/usr/local/include
|
||||
```
|
||||
|
||||
The instances provided allow displaying images and text with markup using just one line:
|
||||
```haskell
|
||||
import qualified Data.ByteString as B
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
@ -1,22 +1,22 @@
|
||||
-- Initial ihaskell-display.cabal generated by cabal init. For further
|
||||
-- Initial ihaskell-display.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: ihaskell-magic
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.3.0.1
|
||||
version: 0.2.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instances for bytestrings
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/IHaskell
|
||||
@ -30,34 +30,39 @@ license-file: LICENSE
|
||||
-- The package author(s).
|
||||
author: Adam Vogt
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Magic
|
||||
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
classy-prelude >=0.6,
|
||||
magic >= 1.0.8,
|
||||
text,
|
||||
bytestring,
|
||||
@ -65,10 +70,10 @@ library
|
||||
base64-bytestring,
|
||||
ipython-kernel,
|
||||
ihaskell >= 0.5
|
||||
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
|
||||
|
@ -1,44 +0,0 @@
|
||||
module IHaskell.Display.Matplotlib where
|
||||
|
||||
import qualified Data.ByteString.Char8 as Char
|
||||
import qualified Data.ByteString.UTF8 as BSU
|
||||
import qualified Data.Text.Encoding as T.Encoding
|
||||
import System.IO.Temp
|
||||
import System.FilePath ((</>))
|
||||
import Graphics.Matplotlib
|
||||
import IHaskell.Display
|
||||
|
||||
instance IHaskellDisplay Matplotlib where
|
||||
display = graphDataDisplayBoth
|
||||
|
||||
-- Width and height
|
||||
w, h :: Int
|
||||
w = 300
|
||||
h = 300
|
||||
|
||||
graphDataPNG :: Matplotlib -> IO DisplayData
|
||||
graphDataPNG m = do
|
||||
withSystemTempDirectory "ihaskell-matplotlib" $ \tmpdir -> do
|
||||
let path = tmpdir </> "ihaskell-matplotlib.png"
|
||||
|
||||
-- Write the image.
|
||||
res <- file path m
|
||||
case res of
|
||||
Left _ -> error "Matplotlib could not generate an immage"
|
||||
Right _ -> do
|
||||
-- Read back, and convert to base64.
|
||||
imgData <- Char.readFile path
|
||||
return $ png w h $ base64 imgData
|
||||
|
||||
graphDataSVG :: Matplotlib -> IO DisplayData
|
||||
graphDataSVG m = do
|
||||
res <- toSvg m
|
||||
case res of
|
||||
Left s -> error s
|
||||
Right f -> return $ svg $ T.Encoding.decodeUtf8 $ BSU.fromString f
|
||||
|
||||
graphDataDisplayBoth :: Matplotlib -> IO Display
|
||||
graphDataDisplayBoth fig = do
|
||||
pngDisp <- graphDataPNG fig
|
||||
svgDisp <- graphDataSVG fig
|
||||
return $ Display [pngDisp, svgDisp]
|
@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2025 Andrea Rossato andrea.rossato@unitn.it
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
File diff suppressed because one or more lines are too long
@ -1,3 +0,0 @@
|
||||
import Distribution.Simple
|
||||
|
||||
main = defaultMain
|
@ -1,69 +0,0 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-matplotlib
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.1
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instance for matplotlib (from matplotlib package)
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: MIT
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENSE
|
||||
|
||||
-- The package author(s).
|
||||
author: Andrea Rossatoe <andrea.rossato@unitn.it>
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: Andrea Rossato <andrea.rossato@unitn.it>,
|
||||
Andrew Gibiansky <andrew.gibiansky@gmail.com>
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Matplotlib
|
||||
|
||||
ghc-options: -O -Wall -Wno-orphans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
bytestring,
|
||||
utf8-string,
|
||||
text,
|
||||
temporary,
|
||||
filepath,
|
||||
matplotlib,
|
||||
ihaskell >= 0.6.2
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
49
ihaskell-display/ihaskell-parsec/IHaskell/Display/Parsec.hs
Normal file
49
ihaskell-display/ihaskell-parsec/IHaskell/Display/Parsec.hs
Normal file
@ -0,0 +1,49 @@
|
||||
{-# LANGUAGE NoImplicitPrelude, TypeSynonymInstances, QuasiQuotes, FlexibleInstances, OverloadedStrings #-}
|
||||
|
||||
module IHaskell.Display.Parsec () where
|
||||
|
||||
import ClassyPrelude hiding (fromList)
|
||||
import System.Random
|
||||
import Data.String.Here
|
||||
import Data.HashMap.Strict as Map
|
||||
|
||||
import Text.Parsec (parse, sourceLine, sourceColumn)
|
||||
import Text.Parsec.String (Parser)
|
||||
import Text.Parsec.Error (errorPos, ParseError)
|
||||
|
||||
import Data.Aeson
|
||||
|
||||
import IHaskell.Display
|
||||
|
||||
instance Show a => IHaskellDisplay (Parser a) where
|
||||
display renderable = return $ many [Display [javascript js], Display [html dom]]
|
||||
where
|
||||
dom = [hereFile|widget.html|]
|
||||
js = [hereFile|widget.js|]
|
||||
|
||||
-- | Text to parse.
|
||||
data ParseText = ParseText String
|
||||
|
||||
instance FromJSON ParseText where
|
||||
parseJSON (Object v) = ParseText <$> v .: "text"
|
||||
parseJSON _ = fail "Expecting object"
|
||||
|
||||
-- | Output of parsing.
|
||||
instance Show a => ToJSON (Either ParseError a) where
|
||||
toJSON (Left err) = object
|
||||
[ "status" .= ("error" :: String)
|
||||
, "line" .= sourceLine (errorPos err)
|
||||
, "col" .= sourceColumn (errorPos err)
|
||||
, "msg" .= show err
|
||||
]
|
||||
toJSON (Right result) = object ["status" .= ("success" :: String), "result" .= show result]
|
||||
|
||||
instance Show a => IHaskellWidget (Parser a) where
|
||||
-- Name for this widget.
|
||||
targetName _ = "parsec"
|
||||
-- When we rece
|
||||
comm widget (Object dict) publisher = do
|
||||
let key = "text" :: Text
|
||||
Just (String text) = Map.lookup key dict
|
||||
result = parse widget "<interactive>" $ unpack text
|
||||
publisher $ toJSON result
|
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Lucas DiCioccio
|
||||
Copyright (c) 2013 Andrew Gibiansky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
2
ihaskell-display/ihaskell-parsec/Setup.hs
Normal file
2
ihaskell-display/ihaskell-parsec/Setup.hs
Normal file
@ -0,0 +1,2 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,19 +1,19 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-gnuplot
|
||||
name: ihaskell-parsec
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.1
|
||||
version: 0.2.1.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instance for Gnuplot (from gnuplot package)
|
||||
synopsis: IHaskell display instances for Parsec
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
@ -25,45 +25,50 @@ license: MIT
|
||||
license-file: LICENSE
|
||||
|
||||
-- The package author(s).
|
||||
author: Doro Rose <dororose@hotmail.com>
|
||||
author: Andrew Gibiansky
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: Doro Rose <dororose@hotmail.com>,
|
||||
Andrew Gibiansky <andrew.gibiansky@gmail.com>
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
extra-source-files: widget.html, widget.js
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Gnuplot
|
||||
|
||||
exposed-modules: IHaskell.Display.Parsec
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
bytestring,
|
||||
text,
|
||||
temporary,
|
||||
filepath,
|
||||
gnuplot >= 0.5.4,
|
||||
ihaskell >= 0.6.2
|
||||
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
aeson >=0.7 && <0.9,
|
||||
unordered-containers,
|
||||
classy-prelude,
|
||||
random >= 1,
|
||||
parsec,
|
||||
here,
|
||||
ihaskell >= 0.5
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
6
ihaskell-display/ihaskell-parsec/widget.html
Normal file
6
ihaskell-display/ihaskell-parsec/widget.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- CodeMirror component -->
|
||||
<link rel="stylesheet" href="/static/components/codemirror/addon/lint/lint.css">
|
||||
|
||||
<!-- Parsec widget DOM -->
|
||||
<form><textarea id="parsec-editor">Insert parser text here...</textarea></form>
|
||||
<pre id="parsec-output"></pre>
|
288
ihaskell-display/ihaskell-parsec/widget.js
Normal file
288
ihaskell-display/ihaskell-parsec/widget.js
Normal file
@ -0,0 +1,288 @@
|
||||
// Only load this script once.
|
||||
var kernel = IPython.notebook.kernel;
|
||||
var initialized = kernel !== undefined && kernel != null;
|
||||
console.log("Initialized", initialized);
|
||||
if (initialized && window.parsecWidgetRegistered === undefined) {
|
||||
|
||||
// Do not load this script again.
|
||||
window.parsecWidgetRegistered = true;
|
||||
|
||||
// Codemirror lint.js
|
||||
// Must be included here, otherwise linting cannot happen the first time the widget is loaded.
|
||||
(function() {
|
||||
"use strict";
|
||||
var GUTTER_ID = "CodeMirror-lint-markers";
|
||||
var SEVERITIES = /^(?:error|warning)$/;
|
||||
|
||||
function showTooltip(e, content) {
|
||||
var tt = document.createElement("div");
|
||||
tt.className = "CodeMirror-lint-tooltip";
|
||||
tt.appendChild(content.cloneNode(true));
|
||||
document.body.appendChild(tt);
|
||||
|
||||
function position(e) {
|
||||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
|
||||
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
|
||||
tt.style.left = (e.clientX + 5) + "px";
|
||||
}
|
||||
CodeMirror.on(document, "mousemove", position);
|
||||
position(e);
|
||||
if (tt.style.opacity != null) tt.style.opacity = 1;
|
||||
return tt;
|
||||
}
|
||||
function rm(elt) {
|
||||
if (elt.parentNode) elt.parentNode.removeChild(elt);
|
||||
}
|
||||
function hideTooltip(tt) {
|
||||
if (!tt.parentNode) return;
|
||||
if (tt.style.opacity == null) rm(tt);
|
||||
tt.style.opacity = 0;
|
||||
setTimeout(function() { rm(tt); }, 600);
|
||||
}
|
||||
|
||||
function showTooltipFor(e, content, node) {
|
||||
var tooltip = showTooltip(e, content);
|
||||
function hide() {
|
||||
CodeMirror.off(node, "mouseout", hide);
|
||||
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
|
||||
}
|
||||
var poll = setInterval(function() {
|
||||
if (tooltip) for (var n = node;; n = n.parentNode) {
|
||||
if (n == document.body) return;
|
||||
if (!n) { hide(); break; }
|
||||
}
|
||||
if (!tooltip) return clearInterval(poll);
|
||||
}, 400);
|
||||
CodeMirror.on(node, "mouseout", hide);
|
||||
}
|
||||
|
||||
function LintState(cm, options, hasGutter) {
|
||||
this.marked = [];
|
||||
this.options = options;
|
||||
this.timeout = null;
|
||||
this.hasGutter = hasGutter;
|
||||
this.onMouseOver = function(e) { onMouseOver(cm, e); };
|
||||
}
|
||||
|
||||
function parseOptions(cm, options) {
|
||||
if (options instanceof Function) return {getAnnotations: options};
|
||||
if (!options || options === true) options = {};
|
||||
if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint");
|
||||
if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)");
|
||||
return options;
|
||||
}
|
||||
|
||||
function clearMarks(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
|
||||
for (var i = 0; i < state.marked.length; ++i)
|
||||
state.marked[i].clear();
|
||||
state.marked.length = 0;
|
||||
}
|
||||
|
||||
function makeMarker(labels, severity, multiple, tooltips) {
|
||||
var marker = document.createElement("div"), inner = marker;
|
||||
marker.className = "CodeMirror-lint-marker-" + severity;
|
||||
if (multiple) {
|
||||
inner = marker.appendChild(document.createElement("div"));
|
||||
inner.className = "CodeMirror-lint-marker-multiple";
|
||||
}
|
||||
|
||||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
|
||||
showTooltipFor(e, labels, inner);
|
||||
});
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
function getMaxSeverity(a, b) {
|
||||
if (a == "error") return a;
|
||||
else return b;
|
||||
}
|
||||
|
||||
function groupByLine(annotations) {
|
||||
var lines = [];
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var ann = annotations[i], line = ann.from.line;
|
||||
(lines[line] || (lines[line] = [])).push(ann);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function annotationTooltip(ann) {
|
||||
var severity = ann.severity;
|
||||
if (!SEVERITIES.test(severity)) severity = "error";
|
||||
var tip = document.createElement("div");
|
||||
tip.className = "CodeMirror-lint-message-" + severity;
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
return tip;
|
||||
}
|
||||
|
||||
function startLinting(cm) {
|
||||
var state = cm.state.lint, options = state.options;
|
||||
if (options.async)
|
||||
options.getAnnotations(cm, updateLinting, options);
|
||||
else
|
||||
updateLinting(cm, options.getAnnotations(cm.getValue(), options.options));
|
||||
}
|
||||
|
||||
function updateLinting(cm, annotationsNotSorted) {
|
||||
clearMarks(cm);
|
||||
var state = cm.state.lint, options = state.options;
|
||||
|
||||
var annotations = groupByLine(annotationsNotSorted);
|
||||
|
||||
for (var line = 0; line < annotations.length; ++line) {
|
||||
var anns = annotations[line];
|
||||
if (!anns) continue;
|
||||
|
||||
var maxSeverity = null;
|
||||
var tipLabel = state.hasGutter && document.createDocumentFragment();
|
||||
|
||||
for (var i = 0; i < anns.length; ++i) {
|
||||
var ann = anns[i];
|
||||
var severity = ann.severity;
|
||||
if (!SEVERITIES.test(severity)) severity = "error";
|
||||
maxSeverity = getMaxSeverity(maxSeverity, severity);
|
||||
|
||||
if (options.formatAnnotation) ann = options.formatAnnotation(ann);
|
||||
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
|
||||
|
||||
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
|
||||
className: "CodeMirror-lint-mark-" + severity,
|
||||
__annotation: ann
|
||||
}));
|
||||
}
|
||||
|
||||
if (state.hasGutter)
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
|
||||
state.options.tooltips));
|
||||
}
|
||||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.lint;
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
|
||||
}
|
||||
|
||||
function popupSpanTooltip(ann, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
showTooltipFor(e, annotationTooltip(ann), target);
|
||||
}
|
||||
|
||||
// When the mouseover fires, the cursor might not actually be over
|
||||
// the character itself yet. These pairs of x,y offsets are used to
|
||||
// probe a few nearby points when no suitable marked range is found.
|
||||
var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0];
|
||||
|
||||
function onMouseOver(cm, e) {
|
||||
if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return;
|
||||
for (var i = 0; i < nearby.length; i += 2) {
|
||||
var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i],
|
||||
top: e.clientY + nearby[i + 1]}));
|
||||
for (var j = 0; j < spans.length; ++j) {
|
||||
var span = spans[j], ann = span.__annotation;
|
||||
if (ann) return popupSpanTooltip(ann, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function optionHandler(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearMarks(cm);
|
||||
cm.off("change", onChange);
|
||||
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
|
||||
delete cm.state.lint;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
var gutters = cm.getOption("gutters"), hasLintGutter = false;
|
||||
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
|
||||
var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
|
||||
cm.on("change", onChange);
|
||||
if (state.options.tooltips != false)
|
||||
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
|
||||
|
||||
startLinting(cm);
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("lintWith", false, optionHandler); // deprecated
|
||||
CodeMirror.defineOption("lint", false, optionHandler); // deprecated
|
||||
})();
|
||||
|
||||
var parsecWidgetCounter = 0;
|
||||
|
||||
// Register the comm target.
|
||||
var ParsecWidget = function (comm) {
|
||||
this.comm = comm;
|
||||
this.comm.on_msg($.proxy(this.handler, this));
|
||||
|
||||
// Get the cell that was probably executed.
|
||||
// The msg_id:cell mapping will make this possible without guessing.
|
||||
this.cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);
|
||||
|
||||
// Store this widget so we can use it from callbacks.
|
||||
var widget = this;
|
||||
|
||||
// Editor options.
|
||||
var options = {
|
||||
lineNumbers: true,
|
||||
// Show parsec errors as lint errors.
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
lintWith: {
|
||||
"getAnnotations": function(cm, update, opts) {
|
||||
var errs = [];
|
||||
if (widget.hasError) {
|
||||
var col = widget.error["col"];
|
||||
var line = widget.error["line"];
|
||||
errs = [{
|
||||
from: CodeMirror.Pos(line - 1, col - 1),
|
||||
to: CodeMirror.Pos(line - 1, col),
|
||||
message: widget.error["msg"],
|
||||
severity: "error"
|
||||
}];
|
||||
}
|
||||
update(cm, errs);
|
||||
},
|
||||
"async": true,
|
||||
}
|
||||
};
|
||||
|
||||
// Create the editor.
|
||||
var out = this.cell.output_area.element;
|
||||
this.textarea = out.find("#parsec-editor")[0];
|
||||
this.output = out.find("#parsec-output")[0];
|
||||
// Give the elements a different name.
|
||||
this.textarea.id += parsecWidgetCounter;
|
||||
this.output.id += parsecWidgetCounter;
|
||||
parsecWidgetCounter++;
|
||||
|
||||
var editor = CodeMirror.fromTextArea(this.textarea, options);
|
||||
var editor = editor;
|
||||
|
||||
// Update every key press.
|
||||
editor.on("keyup", function() {
|
||||
var text = editor.getDoc().getValue();
|
||||
comm.send({"text": text});
|
||||
});
|
||||
};
|
||||
|
||||
ParsecWidget.prototype.handler = function(msg) {
|
||||
var data = msg.content.data;
|
||||
this.hasError = (data["status"] == "error");
|
||||
console.log(this.hasError);
|
||||
if (this.hasError) {
|
||||
this.output.innerHTML = data["msg"];
|
||||
this.error = data;
|
||||
} else {
|
||||
this.output.innerHTML = data["result"];
|
||||
}
|
||||
};
|
||||
|
||||
// Register this widget.
|
||||
IPython.notebook.kernel.comm_manager.register_target('parsec', IPython.utils.always_new(ParsecWidget));
|
||||
console.log("Registering Parsec widget.");
|
||||
}
|
@ -1,46 +1,46 @@
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
|
||||
module IHaskell.Display.Plot where
|
||||
|
||||
import ClassyPrelude
|
||||
|
||||
import qualified Data.ByteString.Char8 as Char
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.Text.Encoding as T.Encoding
|
||||
|
||||
import Graphics.Rendering.Plot
|
||||
import Control.Monad (void)
|
||||
import Control.Applicative ((<$>))
|
||||
import System.IO.Temp
|
||||
import System.FilePath ((</>))
|
||||
|
||||
import IHaskell.Display
|
||||
|
||||
instance IHaskellDisplay (Figure a) where
|
||||
display fig = do
|
||||
let figure = void fig
|
||||
let figure = fig >> return ()
|
||||
pngDisp <- figureData figure PNG
|
||||
svgDisp <- figureData figure SVG
|
||||
return $ Display [pngDisp, svgDisp]
|
||||
|
||||
figureData :: Figure () -> OutputType -> IO DisplayData
|
||||
figureData figure format = do
|
||||
withSystemTempDirectory "ihaskell-plot" $ \tmpdir -> do
|
||||
switchToTmpDir
|
||||
|
||||
-- Width and height
|
||||
let size = 300
|
||||
w = size
|
||||
h = size
|
||||
-- Width and height
|
||||
let size = 300
|
||||
w = size
|
||||
h = size
|
||||
|
||||
let path = case format of
|
||||
PNG -> tmpdir </> "ihaskell-plot.png"
|
||||
SVG -> tmpdir </> "ihaslell-plot.svg"
|
||||
_ -> error "Unreachable case"
|
||||
-- Write the image.
|
||||
let fname = ".ihaskell-plot." ++ extension format
|
||||
writeFigure format fname (w, h) figure
|
||||
|
||||
-- Write the image.
|
||||
writeFigure format path (w, h) figure
|
||||
-- Read back, and convert to base64.
|
||||
imgData <- readFile fname
|
||||
let value =
|
||||
case format of
|
||||
PNG -> png w h $ base64 imgData
|
||||
SVG -> svg $ Char.unpack imgData
|
||||
_ -> error "Unsupported format for display"
|
||||
|
||||
case format of
|
||||
PNG -> do
|
||||
-- Read back, and convert to base64.
|
||||
imgData <- Char.readFile path
|
||||
pure $ png w h $ base64 imgData
|
||||
SVG -> do
|
||||
imgData <- BS.readFile path
|
||||
pure $ svg $ T.Encoding.decodeUtf8 imgData
|
||||
_ -> error "Unreachable case"
|
||||
return value
|
||||
|
||||
where
|
||||
extension SVG = "svg"
|
||||
extension PNG = "png"
|
||||
extension _ = ""
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
@ -1,19 +1,19 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-plot
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.3.0.1
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instance for Plot (from plot package)
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
-- description:
|
||||
|
||||
-- URL for the project homepage or repository.
|
||||
homepage: http://www.github.com/gibiansky/ihaskell
|
||||
@ -27,44 +27,45 @@ license-file: LICENSE
|
||||
-- The package author(s).
|
||||
author: Sumit Sahrawat <sumit.sahrawat.apm13@itbhu.ac.in>
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: Sumit Sahrawat <sumit.sahrawat.apm13@itbhu.ac.in>,
|
||||
Andrew Gibiansky <andrew.gibiansky@gmail.com>
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
-- extra-source-files:
|
||||
-- extra-source-files:
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.16
|
||||
|
||||
library
|
||||
-- Modules exported by the library.
|
||||
exposed-modules: IHaskell.Display.Plot
|
||||
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.9 && <5,
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
classy-prelude >= 0.10.5,
|
||||
plot,
|
||||
bytestring,
|
||||
text,
|
||||
temporary,
|
||||
filepath,
|
||||
hmatrix >= 0.10,
|
||||
ihaskell >= 0.6.2
|
||||
|
||||
ihaskell >= 0.5
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: ihaskell-rlangqq
|
||||
version: 0.3.0.0
|
||||
version: 0.2.1.1
|
||||
synopsis: a rDisp quasiquote to show plots from Rlang-QQ in IHaskell
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
@ -7,22 +7,22 @@ author: Adam Vogt <vogt.adam@gmail.com>
|
||||
maintainer: Adam Vogt <vogt.adam@gmail.com>
|
||||
category: Development
|
||||
build-type: Simple
|
||||
cabal-version: 1.16
|
||||
cabal-version: >=1.10
|
||||
|
||||
library
|
||||
exposed-modules: IHaskell.Display.Rlangqq
|
||||
other-extensions: TupleSections, TemplateHaskell
|
||||
build-depends: base <5,
|
||||
Rlang-QQ >= 0.3,
|
||||
directory >=1.2,
|
||||
filepath >=1.3,
|
||||
bytestring >=0.10,
|
||||
base64-bytestring >=1.0,
|
||||
ihaskell >= 0.6.2,
|
||||
ihaskell-blaze >=0.3,
|
||||
blaze-html >=0.6,
|
||||
split >=0.2,
|
||||
directory >=1.2 && <1.3,
|
||||
filepath >=1.3 && <1.5,
|
||||
bytestring >=0.10 && <0.11,
|
||||
base64-bytestring >=1.0 && <1.1,
|
||||
ihaskell >= 0.6.1,
|
||||
ihaskell-blaze >=0.2 && <0.3,
|
||||
blaze-html >=0.6 && <0.9,
|
||||
split >=0.2 && <0.3,
|
||||
stm -any,
|
||||
xformat >=0.1,
|
||||
xformat >=0.1 && <0.2,
|
||||
template-haskell >= 2.8
|
||||
default-language: Haskell2010
|
||||
|
@ -1,3 +1,2 @@
|
||||
import Distribution.Simple
|
||||
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user