diff --git a/INim.nimble b/INim.nimble index 76fb09e..7918e8b 100644 --- a/INim.nimble +++ b/INim.nimble @@ -11,21 +11,12 @@ requires "nim >= 0.14.2" requires "zmq" requires "hmac" requires "nimSHA2" -# Optional: graph -## Write the spec... -# writeFile("nim-spec/kernel.json", r"""{ -# "argv": ["\inim\\nimkernel", "{connection_file}"], -# "display_name": "nim - pure", -# "language": "nim", -# "file_extension": ".nim" -#}""") bin = @["nimkernel"] after install: echo "Saving kernel spec" - echo thisDir() & "nimkernel" - exec(r"nim c --hints:off --d:release kernelspec.nim") + exec(r"nim c -r --hints:off --d:release kernelspec.nim") after build: echo "Saving kernel spec" @@ -33,14 +24,5 @@ after build: # echo thisDir() & r"\nimkernel" #else: # echo thisDir() & "/nimkernel" - exec(r"nim c -d:debugBuild kernelspec.nim") - -task setup, "Setup the Kernel": - echo "Saving kernel spec" - exec(r"nim c kernelspec.nim") - echo "Building Kernel" - exec(r"nim c --threads:on nimkernel.nim") # compile kernel - exec(r"jupyter-kernelspec install nim-spec --user") # install the spec - -task buildkernel, "Build the Kernel": - exec(r"nim c --threads:on nimkernel.nim") # compile kernel + exec(r"nim c -r --hints:off -d:debugBuild kernelspec.nim") + \ No newline at end of file diff --git a/README.md b/README.md index cbaeca1..db22209 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,12 @@ Note that [ZeroMQ](http://zeromq.org/intro:get-the-software) is dinamically link Magics: ------- +Arguments between square brackets are optional. -**passing flags** -`#>flags < --some > < --d:flag >` +###passing flags + +`#>flags [flag1 flag2 ...] >` Pass flags to nim compiler, default is `--hints:off --verbosity:0 -d:release`. Passing new flags overwrites all other previous flags, even default ones. Example: @@ -60,12 +62,13 @@ else: ``` Outputs: ``` +# A lot of compilation info because verbosity is reset to 1, then hi test defined ``` -**inlining a plot** -`#>inlineplot ` +###inlining a plot +`#>inlineplot [width height]` Enable plotting. This uses a simplified wrapper around matplotlib, see [pyplot](inim/pyplot.nim) Example: ```nim @@ -76,14 +79,18 @@ show: legend() # show the legend, in this case y=x ``` -**delete old temp files** +###reset and clear `#>clear all` +### use tcc +`#>tcc [absolute/path/to/libtcc]` + State: ------ - Compiles and runs code. - Compiler output and results are shown. - Basic 2d plotting +- Temporarily use `custom.js` to load nim highlighting - **Context partially shared**. - **FIXME** code at top level in a block is run in every subsequent block. As a workaround, use `when isMainModule:` to avoid this. diff --git a/kernelspec.nim b/kernelspec.nim index d35b31c..c2ee5a8 100644 --- a/kernelspec.nim +++ b/kernelspec.nim @@ -1,5 +1,5 @@ static: - from os import getHomeDir,walkDir,`/`,PathComponent,execShellCmd,parentDir + from os import getHomeDir,walkDir,`/`,PathComponent,execShellCmd,parentDir,existsFile,existsDir,createDir from strutils import contains import json @@ -11,10 +11,24 @@ static: for s in walkDir(nimblePkgsDir): if s.kind == pcDir and s.path.contains("INim"): return s.path + # Save the kernel spec let kernelspec = %*{ "argv": [getPkgDir() / "nimkernel", "{connection_file}"], "display_name": "Nim", "language": "nim", "file_extension": ".nim" } + writeFile(getPkgDir()/"nim-spec"/"kernel.json", $kernelspec) - echo staticExec(r"jupyter-kernelspec install " & getPkgDir() / "nim-spec" & " --user") # install the spec \ No newline at end of file + echo staticExec(r"jupyter-kernelspec install " & getPkgDir() / "nim-spec" & " --user") # install the spec + +# Append custom js +var custompath = getHomeDir()/".jupyter"/"custom"/"custom.js" +createDir(parentDir(custompath)) # create the dirs we need to store custom.js +proc appendCustom(f:string)= + var f = open(getHomeDir()/".jupyter"/"custom"/"custom.js",fmAppend) + + f.write(readFile(getPkgDir()/"nim-mode"/"custom.js")) + f.close() + +if existsDir(parentDir(custompath)): appendCustom(custompath) +else: echo "Could not install highlighting, refer to github.com/stisa/INim for instructions to manually do this" diff --git a/nim-mode/custom.js b/nim-mode/custom.js new file mode 100644 index 0000000..c4d3271 --- /dev/null +++ b/nim-mode/custom.js @@ -0,0 +1,378 @@ +$([IPython.events]).on('app_initialized.NotebookApp', function(){ + // Define and load a nim codemirror mode. Won't be needed once a codemirror mode for nim is merged into codemirror' + //Original: https://github.com/zah/nim.lt/blob/master/codemirror/nimrod.js + + CodeMirror.defineMode("nim", function(conf, parserConf) { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var operators = new RegExp("\\=\\+\\-\\*\\/\\<\\>\\@\\$\\~\\&\\%\\|\\!\\?\\^\\:\\\\"); + var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + + var commonkeywords = ['addr', 'asm', 'atomic', + 'bind', 'block', 'break', 'case', 'cast', + 'const', 'continue', 'converter', + 'discard', 'distinct', 'do', + 'elif', 'else', 'end', 'enum', 'except', 'export', + 'finally', 'for', 'from', + 'generic', + 'if', 'import', 'include', 'interface', 'iterator', + 'lambda', 'let', + 'macro', 'method', 'mixin', 'nil', + 'object', 'out', + 'proc', 'ptr', + 'raise', 'ref', 'return', + 'shared', 'static', + 'template', 'try', 'tuple', 'type', + 'using', + 'var', + 'when', 'while', 'with', 'without', + 'yield', + + // keyword operators + 'shl', 'shr', 'and', 'or', 'xor', 'not', + 'div', 'mod', 'is', 'isnot', 'in', 'as', 'of']; + + var commonBuiltins = ["int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", + "uint32", "uint64", "float", "float32", "float64", "bool", "char", + "string", "cstring", "pointer", "range", "array", "openarray", + "seq", "set", "Byte", "Natural", "Positive", "TObject", "PObject", + "Conversion", "TResult", "TAddress", "BiggestInt", "BiggestFloat", + "cchar", "cschar", "cshort", "cint", "csize", "cuchar", "cushort", + "clong", "clonglong", "cfloat", "cdouble", "clongdouble", "cuint", + "culong", "culonglong", "cchar", "cstringArray", "TEndian", "PFloat32", + "PFloat64", "PInt64", "PInt32", "TGC_Strategy", "TFile", "TFileMode", + "TFileHandle", "isMainModule", "CompileDate", "CompileTime", "NimVersion", + "NimMajor", "NimMinor", "NimPatch", "cpuEndian", "hostOS", "hostCPU", + "inf", "neginf", "nan", "QuitSuccess", "QuitFailure", "dbgLineHook", "stdin", + "stdout", "stderr", "defined", "new", "high", "low", "sizeof", "succ", "pred", + "inc", "dec", "newSeq", "len", "incl", "excl", "card", "ord", "chr", "ze", + "ze64", "toU8", "toU16", "toU32", "abs", "min", "max", "add", "repr", "contains", + "toFloat", "toBiggestFloat", "toInt", "toBiggestInt", "addQuitProc", "copy", + "setLen", "newString", "zeroMem", "copyMem", "moveMem", "equalMem", "alloc", + "alloc0", "realloc", "dealloc", "setLen", "assert", "swap", "getRefcount", + "getCurrentException", "Msg", "getOccupiedMem", "getFreeMem", "getTotalMem", + "isNil", "seqToPtr", "find", "pop", "GC_disable", "GC_enable", "GC_fullCollect", + "GC_setStrategy", "GC_enableMarkAnd", "Sweep", "GC_disableMarkAnd", "Sweep", + "GC_getStatistics", "GC_ref", "GC_ref", "GC_ref", "GC_unref", "GC_unref", + "GC_unref", "quit", "OpenFile", "OpenFile", "CloseFile", "EndOfFile", + "readChar", "FlushFile", "readFile", "write", "readLine", "writeln", + "writeln", "getFileSize", "ReadBytes", "ReadChars", "readBuffer", + "writeBytes", "writeChars", "writeBuffer", "setFilePos", "getFilePos", + "fileHandle", "countdown", "countup", "items", "lines", + "true", "false", + + // exceptions + "E_Base", "EAsynch", "ESynch", "ESystem", "EIO", "EOS", "ERessourceExhausted", + "EArithmetic", "EDivByZero", "EOverflow", "EAccessViolation", "EAssertionFailed", + "EControlC", "EInvalidValue", "EOutOfMemory", "EInvalidIndex", "EInvalidField", + "EOutOfRange", "EStackOverflow", "ENoExceptionToReraise", "EInvalidObjectAssignment", + "EInvalidObject", "EInvalidLibrary", "EInvalidKey", "EInvalidObjectConversion", + "EFloatingPoint", "EFloatInvalidOp", "EFloatDivByZero", "EFloatOverflow", + "EFloatInexact", "EDeadThrea"]; + + if(parserConf.extra_keywords != undefined) + commonkeywords = commonkeywords.concat(parserConf.extra_keywords); + + if(parserConf.extra_builtins != undefined) + commonBuiltins = commonBuiltins.concat(parserConf.extra_builtins); + + var keywords = wordRegexp(commonkeywords); + var builtins = wordRegexp(commonBuiltins); + + var indentInfo = null; + + var stringPrefixes = new RegExp("^(('{3}|\"{3}|['\"]))", "i"); + + // tokenizers + function tokenBase(stream, state) { + // Handle scope changes + if (stream.sol()) { + var scopeOffset = state.scopes[0].offset; + if (stream.eatSpace()) { + var lineOffset = stream.indentation(); + if (lineOffset > scopeOffset) { + indentInfo = 'indent'; + } else if (lineOffset < scopeOffset) { + indentInfo = 'dedent'; + } + return null; + } else { + if (scopeOffset > 0) { + dedent(stream, state); + } + } + } + + if (stream.eatSpace()) + return null; + + var ch = stream.peek(); + + // Handle Comments + if (ch === '#') { + stream.skipToEnd(); + return 'comment'; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.]/, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } + if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } + if (stream.match(/^\.\d+/)) { floatLiteral = true; } + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return 'number'; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; } + // Binary + if (stream.match(/^0b[01]+/i)) { intLiteral = true; } + // Octal + if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; } + // Decimal + if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return 'number'; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + if (stream.match(operators)) + return 'operator'; + + if (stream.match(keywords)) + return 'keyword'; + + if (stream.match(builtins)) + return 'builtin'; + + if (stream.match(identifiers)) { + if (state.lastToken != null && + state.lastToken.match(/proc|iterator|macro|template|class|converter/)) { + return 'def'; + } + + return 'variable'; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + var singleline = delimiter.length == 1; + var OUTCLASS = 'string'; + + function tokenString(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"\\]/); + if (stream.eat('\\')) { + stream.next(); + if (singleline && stream.eol()) { + return OUTCLASS; + } + } else if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + return ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return OUTCLASS; + } + + tokenString.isString = true; + return tokenString; + } + + function indent(stream, state, type) { + type = type || 'nim'; + var indentUnit = 0; + if (type === 'nim') { + if (state.scopes[0].type !== 'nim') { + state.scopes[0].offset = stream.indentation(); + return; + } + for (var i = 0; i < state.scopes.length; ++i) { + if (state.scopes[i].type === 'nim') { + indentUnit = state.scopes[i].offset + conf.indentUnit; + break; + } + } + } else { + indentUnit = stream.column() + stream.current().length; + } + + state.scopes.unshift({ + offset: indentUnit, + type: type + }); + } + + function dedent(stream, state, type) { + type = type || 'nim'; + if (state.scopes.length == 1) return; + if (state.scopes[0].type === 'nim') { + var _indent = stream.indentation(); + var _indent_index = -1; + for (var i = 0; i < state.scopes.length; ++i) { + if (_indent === state.scopes[i].offset) { + _indent_index = i; + break; + } + } + if (_indent_index === -1) { + return true; + } + while (state.scopes[0].offset !== _indent) { + state.scopes.shift(); + } + return false; + } else { + if (type === 'nim') { + state.scopes[0].offset = stream.indentation(); + return false; + } else { + if (state.scopes[0].type != type) { + return true; + } + state.scopes.shift(); + return false; + } + } + } + + function tokenLexer(stream, state) { + indentInfo = null; + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current === '.') { + style = stream.match(identifiers, false) ? null : ERRORCLASS; + if (style === null && state.lastStyle === 'meta') { + // Apply 'meta' style to '.' connected identifiers when + // appropriate. + style = 'meta'; + } + return style; + } + + if ((style === 'variable' || style === 'builtin') + && state.lastStyle === 'meta') { + style = 'meta'; + } + + // Handle scope changes. + if (current.match(/return|break|continue|raise/) || + (current === 'discard' && stream.eol())) + state.dedent += 1; + + if (current === 'lambda' || current === 'proc') + state.lambda = true; + + var delimiter_index = '[({'.indexOf(current); + + if (delimiter_index !== -1) { + indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1)); + } + else if(stream.eol() && current.match(/\=|\:|import|include|type|const|var|let/)) { + indent(stream, state); + } + + if (indentInfo === 'dedent') { + if (dedent(stream, state)) { + return ERRORCLASS; + } + } + + delimiter_index = '])}'.indexOf(current); + if (delimiter_index !== -1) { + if (dedent(stream, state, current)) { + return ERRORCLASS; + } + } + + if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'nim') { + if (state.scopes.length > 1) state.scopes.shift(); + state.dedent -= 1; + } + + return style; + } + + var external = { + startState: function(basecolumn) { + return { + tokenize: tokenBase, + scopes: [{offset:basecolumn || 0, type:'nim'}], + lastStyle: null, + lastToken: null, + lambda: false, + dedent: 0 + }; + }, + + token: function(stream, state) { + var style = tokenLexer(stream, state); + + state.lastStyle = style; + + var current = stream.current(); + if (current && style) + state.lastToken = current; + + if (stream.eol() && state.lambda) + state.lambda = false; + + return style; + }, + + indent: function(state) { + if (state.tokenize != tokenBase) + return state.tokenize.isString ? CodeMirror.Pass : 0; + + return state.scopes[0].offset; + }, + + lineComment: "#", + fold: "indent" + }; + + return external; + }); + + CodeMirror.defineMIME("text/x-nim", "nim"); + +});