mirror of
https://github.com/IHaskell/IHaskell.git
synced 2025-04-20 05:16:09 +00:00
Reformat; remove ihaskell-parsec
This commit is contained in:
parent
532cd190bc
commit
a7400ea033
ihaskell-display/ihaskell-parsec
ipython-kernel
@ -1,52 +0,0 @@
|
||||
{-# LANGUAGE TypeSynonymInstances, QuasiQuotes, FlexibleInstances, OverloadedStrings #-}
|
||||
|
||||
module IHaskell.Display.Parsec () where
|
||||
|
||||
import System.Random
|
||||
import Data.String.Here
|
||||
import Data.HashMap.Strict as Map
|
||||
import Control.Applicative ((<$>))
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Data.Text (Text)
|
||||
|
||||
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>" $ T.unpack text
|
||||
publisher $ toJSON result
|
@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
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
|
||||
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.
|
@ -1,3 +0,0 @@
|
||||
import Distribution.Simple
|
||||
|
||||
main = defaultMain
|
@ -1,74 +0,0 @@
|
||||
-- The name of the package.
|
||||
name: ihaskell-parsec
|
||||
|
||||
-- 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.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: IHaskell display instances for Parsec
|
||||
|
||||
-- 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: Andrew Gibiansky
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: andrew.gibiansky@gmail.com
|
||||
|
||||
-- A copyright notice.
|
||||
-- copyright:
|
||||
|
||||
category: Development
|
||||
|
||||
build-type: Simple
|
||||
|
||||
extra-source-files: widget.html, widget.js
|
||||
-- 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.Parsec
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
-- other-modules:
|
||||
|
||||
-- Language extensions.
|
||||
default-extensions: DoAndIfThenElse
|
||||
OverloadedStrings
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.6 && <4.9,
|
||||
aeson >=0.7 && <0.10,
|
||||
text,
|
||||
unordered-containers,
|
||||
random >= 1,
|
||||
parsec,
|
||||
here,
|
||||
ihaskell >= 0.5
|
||||
|
||||
-- Directories containing source files.
|
||||
-- hs-source-dirs:
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
@ -1,6 +0,0 @@
|
||||
<!-- 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>
|
@ -1,288 +0,0 @@
|
||||
// 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.");
|
||||
}
|
@ -265,4 +265,5 @@ main = do
|
||||
_ -> do
|
||||
putStrLn "Usage:"
|
||||
putStrLn "simple-calc-example install -- set up the kernelspec"
|
||||
putStrLn "simple-calc-example kernel FILE -- run a kernel with FILE for communication with the frontend"
|
||||
putStrLn
|
||||
"simple-calc-example kernel FILE -- run a kernel with FILE for communication with the frontend"
|
||||
|
@ -2,13 +2,13 @@ module Main where
|
||||
|
||||
import qualified Data.Text as T
|
||||
|
||||
import System.Environment (getArgs)
|
||||
import System.Environment (getArgs)
|
||||
|
||||
import Text.Parsec
|
||||
import Text.Parsec.String
|
||||
import Text.Parsec
|
||||
import Text.Parsec.String
|
||||
|
||||
import IHaskell.IPython.EasyKernel (easyKernel, installKernelspec, KernelConfig(..))
|
||||
import IHaskell.IPython.Types
|
||||
import IHaskell.IPython.EasyKernel (easyKernel, installKernelspec, KernelConfig(..))
|
||||
import IHaskell.IPython.Types
|
||||
|
||||
-- Define the actual language!
|
||||
data Expr = Plus Expr Expr
|
||||
@ -47,12 +47,13 @@ parseExpr str =
|
||||
char ','
|
||||
y <- expr
|
||||
char ')'
|
||||
return $ case func of
|
||||
"plus" -> Plus x y
|
||||
"minus" -> Minus x y
|
||||
"times" -> Times x y
|
||||
"div" -> Div x y
|
||||
"exp" -> Exp x y
|
||||
return $
|
||||
case func of
|
||||
"plus" -> Plus x y
|
||||
"minus" -> Minus x y
|
||||
"times" -> Times x y
|
||||
"div" -> Div x y
|
||||
"exp" -> Exp x y
|
||||
|
||||
languageConfig :: LanguageInfo
|
||||
languageConfig = LanguageInfo
|
||||
@ -73,11 +74,10 @@ displayString :: String -> [DisplayData]
|
||||
displayString str = [DisplayData PlainText (T.pack str)]
|
||||
|
||||
languageCompletion :: Monad m => T.Text -> Int -> m (T.Text, [T.Text])
|
||||
languageCompletion code pos = return $
|
||||
languageCompletion code pos = return $
|
||||
let (before, _) = T.splitAt pos code
|
||||
word = last $ T.words $ T.map replace before
|
||||
in (word, map T.pack $ matches $ T.unpack word)
|
||||
|
||||
where
|
||||
matches :: String -> [String]
|
||||
matches word =
|
||||
@ -92,7 +92,7 @@ languageCompletion code pos = return $
|
||||
replace '(' = ' '
|
||||
replace ')' = ' '
|
||||
replace ',' = ' '
|
||||
replace x = x
|
||||
replace x = x
|
||||
|
||||
languageInspect :: Monad m => T.Text -> Int -> m (Maybe [DisplayData])
|
||||
languageInspect _ _ = return $
|
||||
@ -120,7 +120,6 @@ languageRun code init intermediate = do
|
||||
Left err -> err
|
||||
Right expr -> show (eval expr), IHaskell.IPython.Types.Ok, "")
|
||||
|
||||
|
||||
simpleConfig :: KernelConfig IO String String
|
||||
simpleConfig = KernelConfig
|
||||
{ kernelLanguageInfo = languageConfig
|
||||
@ -145,4 +144,5 @@ main = do
|
||||
_ -> do
|
||||
putStrLn "Usage:"
|
||||
putStrLn "fun-calc-example install -- set up the kernelspec"
|
||||
putStrLn "fun-calc-example kernel FILE -- run a kernel with FILE for communication with the frontend"
|
||||
putStrLn
|
||||
"fun-calc-example kernel FILE -- run a kernel with FILE for communication with the frontend"
|
||||
|
@ -11,17 +11,16 @@
|
||||
--
|
||||
-- = Kernel Specs
|
||||
--
|
||||
-- To run your kernel, you will need to install the kernelspec into the Jupyter namespace.
|
||||
-- If your kernel name is `kernel`, you will need to run the command:
|
||||
-- To run your kernel, you will need to install the kernelspec into the Jupyter namespace. If your
|
||||
-- kernel name is `kernel`, you will need to run the command:
|
||||
--
|
||||
-- > kernel install
|
||||
--
|
||||
-- This will inform Jupyter of the kernel so that it may be used.
|
||||
--
|
||||
-- == Further profile improvements
|
||||
-- Consult the IPython documentation along with the generated profile
|
||||
-- source code for further configuration of the frontend, including
|
||||
-- syntax highlighting, logos, help text, and so forth.
|
||||
-- == Further profile improvements Consult the IPython documentation along with the generated
|
||||
-- profile source code for further configuration of the frontend, including syntax highlighting,
|
||||
-- logos, help text, and so forth.
|
||||
module IHaskell.IPython.EasyKernel (easyKernel, installKernelspec, KernelConfig(..)) where
|
||||
|
||||
import Data.Aeson (decode, encode)
|
||||
@ -99,7 +98,6 @@ installKernelspec config replace installPrefixMay =
|
||||
installPrefixFlag = maybe ["--user"] (\prefix -> ["--prefix", prefix]) installPrefixMay
|
||||
cmd = concat [["kernelspec", "install"], installPrefixFlag, [kernelDir], replaceFlag]
|
||||
void $ rawSystem "ipython" cmd
|
||||
|
||||
where
|
||||
withTmpDir act = do
|
||||
tmp <- getTemporaryDirectory
|
||||
|
Loading…
x
Reference in New Issue
Block a user