From 9612a03f8c58493a4d88ad10c24002d451a45f4f Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Tue, 20 Oct 2015 12:13:05 +0200 Subject: [PATCH 01/20] Fixed IntelliSense and syntax highlighting --- IfSharp.sln | 11 +- ipython-profile/ipython_config.py | 5 +- ipython-profile/kernel.js | 164 ++++++++++++++++ ipython-profile/static/custom/custom.js | 177 ------------------ .../static/custom/{custom.css => fsharp.css} | 0 src/IfSharp.Kernel/App.fs | 79 +++++--- src/IfSharp.Kernel/IfSharpResources.fs | 9 +- src/IfSharp.Kernel/IfSharpResources.resx | 20 +- src/IfSharp.Kernel/NuGetManager.fs | 58 +++--- src/IfSharp.Kernel/ShellMessages.fs | 9 + src/IfSharpConsole/Program.cs | 3 + 11 files changed, 297 insertions(+), 238 deletions(-) create mode 100644 ipython-profile/kernel.js delete mode 100644 ipython-profile/static/custom/custom.js rename ipython-profile/static/custom/{custom.css => fsharp.css} (100%) diff --git a/IfSharp.sln b/IfSharp.sln index 2a00bbc..3e15958 100644 --- a/IfSharp.sln +++ b/IfSharp.sln @@ -51,6 +51,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ipython-profile", "ipython- ProjectSection(SolutionItems) = preProject ipython-profile\static\custom\ifsharp_logo.png = ipython-profile\static\custom\ifsharp_logo.png ipython-profile\ipython_config.py = ipython-profile\ipython_config.py + ipython-profile\kernel.js = ipython-profile\kernel.js EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IfSharpConsole", "src\IfSharpConsole\IfSharpConsole.csproj", "{6BD0E996-0AEE-4FC7-8FB9-46E033D0C7F1}" @@ -59,8 +60,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "static", "static", "{45519D EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "custom", "custom", "{3AAFA64D-CBB6-488E-B395-6A1E7CB554CE}" ProjectSection(SolutionItems) = preProject - ipython-profile\static\custom\custom.css = ipython-profile\static\custom\custom.css - ipython-profile\static\custom\custom.js = ipython-profile\static\custom\custom.js + ipython-profile\static\custom\fsharp.css = ipython-profile\static\custom\fsharp.css ipython-profile\static\custom\fsharp.js = ipython-profile\static\custom\fsharp.js ipython-profile\static\custom\ifsharp_logo.png = ipython-profile\static\custom\ifsharp_logo.png ipython-profile\static\custom\webintellisense-codemirror.js = ipython-profile\static\custom\webintellisense-codemirror.js @@ -102,6 +102,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{8BA6BD71-43A lib\README.md = lib\README.md EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "kernel-spec", "kernel-spec", "{4D56C9F0-7F98-4587-A320-98C06876AC9B}" + ProjectSection(SolutionItems) = preProject + kernel-spec\kernel.json = kernel-spec\kernel.json + kernel-spec\logo-32x32.png = kernel-spec\logo-32x32.png + kernel-spec\logo-64x64.png = kernel-spec\logo-64x64.png + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 diff --git a/ipython-profile/ipython_config.py b/ipython-profile/ipython_config.py index 63b4d78..56f1f0e 100644 --- a/ipython-profile/ipython_config.py +++ b/ipython-profile/ipython_config.py @@ -1,4 +1,5 @@ c = get_config() -c.KernelManager.kernel_spec = [r"%s", "{connection_file}"] +c.KernelManager.kernel_spec = [ "mono", r"%kexe", "{connection_file}"] c.Session.key = b'' -c.Session.keyfile = '' \ No newline at end of file +c.Session.keyfile = '' +c.NotebookApp.extra_static_paths = [ r"%kfolder" ] \ No newline at end of file diff --git a/ipython-profile/kernel.js b/ipython-profile/kernel.js new file mode 100644 index 0000000..1c3bcf9 --- /dev/null +++ b/ipython-profile/kernel.js @@ -0,0 +1,164 @@ +define(function () { + + var link = document.createElement("link"); + link.type = "text/css"; + link.rel = "stylesheet"; + link.href = "/static/custom/fsharp.css"; + document.getElementsByTagName("head")[0].appendChild(link); + + require(['codemirror/addon/mode/loadmode']); + + var onload = function () { + + var md = IPython.notebook.metadata; + if (md.language) { + console.log('language already defined and is :', md.language); + } + else { + md.language = 'fsharp'; + console.log('add metadata hint that language is fsharp...'); + } + + require(['/static/custom/fsharp.js']); + + IPython.CodeCell.options_default.cm_config.mode = 'fsharp'; + + // callback called by the end-user + function updateMarkers(data) { + // applies intellisense hooks onto all cells + var cells = getCodeCells(); + data.forEach(function (err) { + var cell = cells.cells[err.CellNumber] + var editor = cell.code_mirror; + + // clear our error marks + editor.doc.getAllMarks() + .forEach(function (m) { + if (m.className === 'br-errormarker') { + m.clear(); + } + }); + + var from = { line: err.StartLine, ch: err.StartColumn }; + var to = { line: err.EndLine, ch: err.EndColumn }; + editor.doc.markText(from, to, { title: err.Message, className: 'br-errormarker' }); + }); + } + + function getCodeCells() { + var results = { codes: [], cells: [], selectedCell: null, selectedIndex: 0 }; + IPython.notebook.get_cells() + .forEach(function (c) { + if (c.cell_type === 'code') { + if (c.selected === true) { + results.selectedCell = c; + results.selectedIndex = results.cells.length; + } + results.cells.push(c); + results.codes.push(c.code_mirror.getValue()); + } + }); + + return results; + } + + require(['/static/custom/webintellisense.js', '/static/custom/webintellisense-codemirror.js'], function () { + // applies intellisense hooks onto a cell + function applyIntellisense(cell) { + if (cell.cell_type !== 'code') { return; } + + var editor = cell.code_mirror; + if (editor.intellisense == null) { + var intellisense = new CodeMirrorIntellisense(editor); + cell.force_highlight('fsharp'); + cell.code_mirror.setOption('theme', 'neat'); + editor.intellisense = intellisense; + + intellisense.addDeclarationTrigger({ keyCode: 190 }); // `.` + intellisense.addDeclarationTrigger({ keyCode: 32, ctrlKey: true, preventDefault: true, type: 'down' }); // `ctrl+space` + intellisense.addDeclarationTrigger({ keyCode: 191 }); // `/` + intellisense.addDeclarationTrigger({ keyCode: 220 }); // `\` + intellisense.addDeclarationTrigger({ keyCode: 222 }); // `"` + intellisense.addDeclarationTrigger({ keyCode: 222, shiftKey: true }); // `"` + intellisense.addMethodsTrigger({ keyCode: 57, shiftKey: true }); // `(` + intellisense.addMethodsTrigger({ keyCode: 48, shiftKey: true });// `)` + intellisense.onMethod(function (item, position) { + + }); + intellisense.onDeclaration(function (item, position) { + var cells = getCodeCells(); + var codes = cells.codes; + var cursor = cells.selectedCell.code_mirror.doc.getCursor(); + var callbacks = { shell: {}, iopub: {} }; + var line = editor.getLine(cursor.line); + var isSlash = item.keyCode === 191 || item.keyCode === 220; + var isQuote = item.keyCode === 222; + + var isLoadOrRef = line.indexOf('#load') === 0 + || line.indexOf('#r') === 0; + + var isStartLoadOrRef = line === '#load "' + || line === '#r "' + || line === '#load @"' + || line === '#r @"'; + + if (isSlash && !isLoadOrRef) { + return; + } + if (isQuote && !isStartLoadOrRef) { + return; + } + + // v2 + callbacks.shell.reply = function (msg) { + intellisense.setDeclarations(msg.content.matches); + if (msg.content.filter_start_index) + intellisense.setStartColumnIndex(msg.content.filter_start_index); + }; + + callbacks.iopub.output = function (msg) { + updateMarkers(msg.content.data.errors); + }; + + // v1 + callbacks.complete_reply = function (data) { + intellisense.setDeclarations(data.matches); + intellisense.setStartColumnIndex(data.filter_start_index); + }; + + callbacks.output = function (msgType, content, metadata) { + updateMarkers(content.data.errors); + }; + + var content = { + text: JSON.stringify(codes), + line: '', + block: JSON.stringify({ selectedIndex: cells.selectedIndex, ch: cursor.ch, line: cursor.line }), + cursor_pos: cursor.ch + }; + + IPython.notebook.kernel.send_shell_message("intellisense_request", content, callbacks, null, null); + }); + } + } + + // applies intellisense hooks onto all cells + IPython.notebook.get_cells() + .forEach(function (cell) { + applyIntellisense(cell); + }); + + // applies intellisense hooks onto cells that are selected + $([IPython.events]).on('create.Cell', function (event, data) { + applyIntellisense(data.cell); + }); + }); + + // replace the image + var img = $('.container img')[0]; + img.src = "/static/custom/ifsharp_logo.png"; + + } + + return { onload: onload } +}) \ No newline at end of file diff --git a/ipython-profile/static/custom/custom.js b/ipython-profile/static/custom/custom.js deleted file mode 100644 index c1b4467..0000000 --- a/ipython-profile/static/custom/custom.js +++ /dev/null @@ -1,177 +0,0 @@ -$([IPython.events]).on('notebook_loaded.Notebook', function () -{ - var md = IPython.notebook.metadata; - if (md.language) - { - console.log('language already defined and is :', md.language); - } - else - { - md.language = 'fsharp'; - console.log('add metadata hint that language is fsharp...'); - } -}); - -$([IPython.events]).on('app_initialized.NotebookApp', function () -{ - require(['custom/fsharp']); - - IPython.CodeCell.options_default.cm_config.mode = 'fsharp'; - - // callback called by the end-user - function updateMarkers(data) - { - // applies intellisense hooks onto all cells - var cells = getCodeCells(); - data.forEach(function (err) - { - var cell = cells.cells[err.CellNumber] - var editor = cell.code_mirror; - - // clear our error marks - editor.doc.getAllMarks() - .forEach(function (m) - { - if (m.className === 'br-errormarker') - { - m.clear(); - } - }); - - var from = { line: err.StartLine, ch: err.StartColumn }; - var to = { line: err.EndLine, ch: err.EndColumn }; - editor.doc.markText(from, to, { title: err.Message, className: 'br-errormarker' }); - }); - } - - function getCodeCells() - { - var results = { codes: [], cells: [], selectedCell: null, selectedIndex: 0 }; - IPython.notebook.get_cells() - .forEach(function (c) - { - if (c.cell_type === 'code') - { - if (c.selected === true) - { - results.selectedCell = c; - results.selectedIndex = results.cells.length; - } - results.cells.push(c); - results.codes.push(c.code_mirror.getValue()); - } - }); - - return results; - } - - require(['custom/webintellisense', 'custom/webintellisense-codemirror'], function () - { - // applies intellisense hooks onto a cell - function applyIntellisense(cell) - { - if (cell.cell_type !== 'code') { return; } - - var editor = cell.code_mirror; - if (editor.intellisense == null) - { - var intellisense = new CodeMirrorIntellisense(editor); - cell.force_highlight('fsharp'); - cell.code_mirror.setOption('theme', 'neat'); - editor.intellisense = intellisense; - - intellisense.addDeclarationTrigger({ keyCode: 190 }); // `.` - intellisense.addDeclarationTrigger({ keyCode: 32, ctrlKey: true, preventDefault: true, type: 'down' }); // `ctrl+space` - intellisense.addDeclarationTrigger({ keyCode: 191 }); // `/` - intellisense.addDeclarationTrigger({ keyCode: 220 }); // `\` - intellisense.addDeclarationTrigger({ keyCode: 222 }); // `"` - intellisense.addDeclarationTrigger({ keyCode: 222, shiftKey: true }); // `"` - intellisense.addMethodsTrigger({ keyCode: 57, shiftKey: true }); // `(` - intellisense.addMethodsTrigger({ keyCode: 48, shiftKey: true });// `)` - intellisense.onMethod(function (item, position) - { - - }); - intellisense.onDeclaration(function (item, position) - { - var cells = getCodeCells(); - var codes = cells.codes; - var cursor = cells.selectedCell.code_mirror.doc.getCursor(); - var callbacks = { shell: {}, iopub: {} }; - var line = editor.getLine(cursor.line); - var isSlash = item.keyCode === 191 || item.keyCode === 220; - var isQuote = item.keyCode === 222; - - var isLoadOrRef = line.indexOf('#load') === 0 - || line.indexOf('#r') === 0; - - var isStartLoadOrRef = line === '#load "' - || line === '#r "' - || line === '#load @"' - || line === '#r @"'; - - if (isSlash && !isLoadOrRef) - { - return; - } - if (isQuote && !isStartLoadOrRef) - { - return; - } - - // v2 - callbacks.shell.reply = function (msg) - { - intellisense.setDeclarations(msg.content.matches); - intellisense.setStartColumnIndex(data.filter_start_index); - }; - - callbacks.iopub.output = function (msg) - { - updateMarkers(msg.content.data.errors); - }; - - // v1 - callbacks.complete_reply = function (data) - { - intellisense.setDeclarations(data.matches); - intellisense.setStartColumnIndex(data.filter_start_index); - }; - - callbacks.output = function (msgType, content, metadata) - { - updateMarkers(content.data.errors); - }; - - var content = { - text: JSON.stringify(codes), - line: '', - block: JSON.stringify({ selectedIndex: cells.selectedIndex, ch: cursor.ch, line: cursor.line }), - cursor_pos: cursor.ch - }; - debugger; - var msg = IPython.notebook.kernel._get_msg("intellisense_request", content); - IPython.notebook.kernel.shell_channel.send(JSON.stringify(msg)); - IPython.notebook.kernel.set_callbacks_for_msg(msg.header.msg_id, callbacks); - }); - } - } - - // applies intellisense hooks onto all cells - IPython.notebook.get_cells() - .forEach(function (cell) - { - applyIntellisense(cell); - }); - - // applies intellisense hooks onto cells that are selected - $([IPython.events]).on('create.Cell', function (event, data) - { - applyIntellisense(data.cell); - }); - }); - - // replace the image - var img = $('.container img')[0]; - img.src = "/static/custom/ifsharp_logo.png"; -}); \ No newline at end of file diff --git a/ipython-profile/static/custom/custom.css b/ipython-profile/static/custom/fsharp.css similarity index 100% rename from ipython-profile/static/custom/custom.css rename to ipython-profile/static/custom/fsharp.css diff --git a/src/IfSharp.Kernel/App.fs b/src/IfSharp.Kernel/App.fs index 7ff2a6b..701c286 100644 --- a/src/IfSharp.Kernel/App.fs +++ b/src/IfSharp.Kernel/App.fs @@ -148,10 +148,12 @@ module App = let InstallAndStart(forceInstall) = let thisExecutable = Assembly.GetEntryAssembly().Location - let appData = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) - let ipythonDir = Path.Combine(appData, ".ipython") - let profileDir = Path.Combine(ipythonDir, "profile_ifsharp") - let staticDir = Path.Combine(profileDir, "static") + let userDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + let appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + let jupyterDir = Path.Combine(appData, "Jupyter") + let kernelsDir = Path.Combine(jupyterDir, "kernels") + let kernelDir = Path.Combine(kernelsDir, "ifsharp") + let staticDir = Path.Combine(kernelDir, "static") let customDir = Path.Combine(staticDir, "custom") let createDir(str) = @@ -159,61 +161,92 @@ module App = Directory.CreateDirectory(str) |> ignore createDir appData - createDir ipythonDir - createDir profileDir + createDir jupyterDir + createDir kernelsDir + createDir kernelDir createDir staticDir createDir customDir - let configFile = Path.Combine(profileDir, "ipython_config.py") + let configFile = Path.Combine(kernelDir, "ipython_config.py") + let configqtFile = Path.Combine(kernelDir, "ipython_qtconsole_config.py") + let kernelFile = Path.Combine(kernelDir, "kernel.json") if forceInstall || (File.Exists(configFile) = false) then printfn "Config file does not exist, performing install..." // write the startup script let codeTemplate = IfSharpResources.ipython_config() - let code = codeTemplate.Replace("%s", thisExecutable) + let code = + match Environment.OSVersion.Platform with + | PlatformID.Win32Windows -> codeTemplate.Replace("\"mono\",", "") + | PlatformID.Win32NT -> codeTemplate.Replace("\"mono\",", "") + | _ -> codeTemplate + let code = code.Replace("%kexe", thisExecutable) + let code = code.Replace("%kfolder", staticDir) printfn "Saving custom config file [%s]" configFile File.WriteAllText(configFile, code) + + let codeqt = IfSharpResources.ipython_qt_config() + printfn "Saving custom qt config file [%s]" codeqt + File.WriteAllText(configqtFile, codeqt) // write custom logo file let logoFile = Path.Combine(customDir, "ifsharp_logo.png") printfn "Saving custom logo [%s]" logoFile IfSharpResources.ifsharp_logo().Save(logoFile) - // write custom css file - let cssFile = Path.Combine(customDir, "custom.css") - printfn "Saving custom css [%s]" cssFile - File.WriteAllText(cssFile, IfSharpResources.custom_css()) + // write fsharp css file + let cssFile = Path.Combine(customDir, "fsharp.css") + printfn "Saving fsharp css [%s]" cssFile + File.WriteAllText(cssFile, IfSharpResources.fsharp_css()) - // write custom js file - let jsFile = Path.Combine(customDir, "custom.js") - printfn "Saving custom js [%s]" jsFile - File.WriteAllText(jsFile, IfSharpResources.custom_js()) + // write kernel js file + let jsFile = Path.Combine(kernelDir, "kernel.js") + printfn "Saving kernel js [%s]" jsFile + File.WriteAllText(jsFile, IfSharpResources.kernel_js()) // write fsharp js file let jsFile = Path.Combine(customDir, "fsharp.js") printfn "Saving fsharp js [%s]" jsFile File.WriteAllText(jsFile, IfSharpResources.fsharp_js()) - // write fsharp js file + // write webintellisense js file let jsFile = Path.Combine(customDir, "webintellisense.js") printfn "Saving webintellisense js [%s]" jsFile File.WriteAllText(jsFile, IfSharpResources.webintellisense_js()) - // write fsharp js file + // write webintellisense-codemirror js file let jsFile = Path.Combine(customDir, "webintellisense-codemirror.js") printfn "Saving webintellisense-codemirror js [%s]" jsFile File.WriteAllText(jsFile, IfSharpResources.webintellisense_codemirror_js()) + // Make the Kernel info folder + let jsonTemplate = IfSharpResources.ifsharp_kernel_json() + let code = + match Environment.OSVersion.Platform with + | PlatformID.Win32Windows -> jsonTemplate.Replace("\"mono\",", "") + | PlatformID.Win32NT -> jsonTemplate.Replace("\"mono\",", "") + | _ -> jsonTemplate + let code = code.Replace("%s", thisExecutable.Replace("\\","\/")) + printfn "Saving custom kernel.json file [%s]" kernelFile + File.WriteAllText(kernelFile, code) + + let logo64File = Path.Combine(kernelDir, "logo-64x64.png") + printfn "Saving kernel icon [%s]" logo64File + IfSharpResources.ifsharp_64logo().Save(logo64File) + + let logo32File = Path.Combine(kernelDir, "logo-32x32.png") + printfn "Saving kernel icon [%s]" logo32File + IfSharpResources.ifsharp_32logo().Save(logo32File) + printfn "Starting ipython..." let p = new Process() - p.StartInfo.FileName <- "ipython" -// p.StartInfo.Arguments <- "notebook --profile ifsharp" - p.StartInfo.Arguments <- "qtconsole --profile ifsharp" - p.StartInfo.WorkingDirectory <- appData + p.StartInfo.FileName <- "jupyter" + p.StartInfo.Arguments <- "notebook --config=" + configFile + p.StartInfo.WorkingDirectory <- userDir // tell the user something bad happened - if p.Start() = false then printfn "Unable to start ipython, please install ipython first" + if p.Start() = false then printfn "Unable to start jupyter, please install jupyter first" /// First argument must be an ipython connection file, blocks forever let Start (args : array) = diff --git a/src/IfSharp.Kernel/IfSharpResources.fs b/src/IfSharp.Kernel/IfSharpResources.fs index 524dbe4..344942c 100644 --- a/src/IfSharp.Kernel/IfSharpResources.fs +++ b/src/IfSharp.Kernel/IfSharpResources.fs @@ -13,10 +13,13 @@ module IfSharpResources = Encoding.UTF8.GetString(array) let ifsharp_logo() = resources.GetObject("ifsharp_logo") :?> System.Drawing.Bitmap - let custom_css() = resources.GetString("custom_css") - let custom_js() = resources.GetString("custom_js") + let fsharp_css() = resources.GetString("fsharp_css") + let kernel_js() = resources.GetString("kernel_js") let fsharp_js() = resources.GetString("fsharp_js") let webintellisense_js() = resources.GetString("webintellisense") let webintellisense_codemirror_js() = resources.GetString("webintellisense-codemirror") let ipython_config() = getString("ipython_config") - + let ipython_qt_config() = getString("qtconsole_config") + let ifsharp_kernel_json() = getString("kernel_json") + let ifsharp_64logo() = resources.GetObject("logo64File") :?> System.Drawing.Bitmap + let ifsharp_32logo() = resources.GetObject("logo32File") :?> System.Drawing.Bitmap diff --git a/src/IfSharp.Kernel/IfSharpResources.resx b/src/IfSharp.Kernel/IfSharpResources.resx index 0aef0aa..819e3b0 100644 --- a/src/IfSharp.Kernel/IfSharpResources.resx +++ b/src/IfSharp.Kernel/IfSharpResources.resx @@ -118,11 +118,11 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\..\ipython-profile\static\custom\custom.css;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\..\ipython-profile\static\custom\fsharp.css;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - - ..\..\ipython-profile\static\custom\custom.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\..\ipython-profile\kernel.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 ..\..\ipython-profile\static\custom\fsharp.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 @@ -133,6 +133,18 @@ ..\..\ipython-profile\ipython_config.py;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\..\kernel-spec\kernel.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\..\kernel-spec\logo-32x32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\..\kernel-spec\logo-64x64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\..\ipython-profile\ipython_qtconsole_config.py;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\..\ipython-profile\static\custom\webintellisense.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 diff --git a/src/IfSharp.Kernel/NuGetManager.fs b/src/IfSharp.Kernel/NuGetManager.fs index fe51168..1e58e1e 100644 --- a/src/IfSharp.Kernel/NuGetManager.fs +++ b/src/IfSharp.Kernel/NuGetManager.fs @@ -176,34 +176,38 @@ type NuGetManager (executingDirectory : string) = else let pkg = installer.FindPackage(nugetPackage, version) - let getCompatibleItems targetFramework items = - let retval, compatibleItems = VersionUtility.TryGetCompatibleItems(targetFramework, items) - if retval then compatibleItems else Seq.empty - - let maxFramework = - // try full framework first - if none is supported, fall back - let fullFrameworks = pkg.GetSupportedFrameworks() |> Seq.filter (fun x -> x.Identifier = ".NETFramework") |> Seq.toArray - if Array.length fullFrameworks > 0 then fullFrameworks |> Array.maxBy (fun x -> x.Version) - else pkg.GetSupportedFrameworks() |> Seq.maxBy (fun x -> x.Version) - - let assemblies = - if not(pkg.PackageAssemblyReferences.IsEmpty()) then - let compatibleAssemblyReferences = - getCompatibleItems maxFramework pkg.PackageAssemblyReferences - |> Seq.collect (fun x -> x.References) - |> Set.ofSeq - pkg.AssemblyReferences - |> Seq.filter (fun x -> compatibleAssemblyReferences.Contains x.Name && x.TargetFramework = maxFramework ) - elif pkg.AssemblyReferences.IsEmpty() then - Seq.empty - else - getCompatibleItems maxFramework pkg.AssemblyReferences - - let frameworkAssemblyReferences = getCompatibleItems maxFramework pkg.FrameworkAssemblies - - packagesCache.Add(key, { Package = Some pkg; Assemblies = assemblies; FrameworkAssemblies = frameworkAssemblyReferences; Error = ""; }) + + if pkg.GetSupportedFrameworks().IsEmpty() then // content-only package + packagesCache.Add(key, { Package = Some pkg; Assemblies = Seq.empty; FrameworkAssemblies = Seq.empty; Error = ""; }); + else + let getCompatibleItems targetFramework items = + let retval, compatibleItems = VersionUtility.TryGetCompatibleItems(targetFramework, items) + if retval then compatibleItems else Seq.empty + + let maxFramework = + // try full framework first - if none is supported, fall back + let fullFrameworks = pkg.GetSupportedFrameworks() |> Seq.filter (fun x -> x.Identifier = ".NETFramework") |> Seq.toArray + if Array.length fullFrameworks > 0 then fullFrameworks |> Array.maxBy (fun x -> x.Version) + else pkg.GetSupportedFrameworks() |> Seq.maxBy (fun x -> x.Version) + + let assemblies = + if not(pkg.PackageAssemblyReferences.IsEmpty()) then + let compatibleAssemblyReferences = + getCompatibleItems maxFramework pkg.PackageAssemblyReferences + |> Seq.collect (fun x -> x.References) + |> Set.ofSeq + pkg.AssemblyReferences + |> Seq.filter (fun x -> compatibleAssemblyReferences.Contains x.Name && x.TargetFramework = maxFramework ) + elif pkg.AssemblyReferences.IsEmpty() then + Seq.empty + else + getCompatibleItems maxFramework pkg.AssemblyReferences + + let frameworkAssemblyReferences = getCompatibleItems maxFramework pkg.FrameworkAssemblies + + packagesCache.Add(key, { Package = Some pkg; Assemblies = assemblies; FrameworkAssemblies = frameworkAssemblyReferences; Error = ""; }) + packagesCache.[key] - ) /// Parses a 'nuget line'. Example #N "[/[/pre]]". diff --git a/src/IfSharp.Kernel/ShellMessages.fs b/src/IfSharp.Kernel/ShellMessages.fs index cf9b5aa..ea52597 100644 --- a/src/IfSharp.Kernel/ShellMessages.fs +++ b/src/IfSharp.Kernel/ShellMessages.fs @@ -301,6 +301,8 @@ type ConnectReply = hb_port: int; // # The port the heartbeat socket is listening on. } +type CommOpen = obj + type KernelRequest = obj type KernelReply = @@ -425,6 +427,9 @@ type ShellMessage = | ConnectRequest of ConnectRequest | ConnectReply of ConnectReply + // comm open? + | CommOpen of CommOpen + // kernel info | KernelRequest of KernelRequest | KernelReply of KernelReply @@ -482,4 +487,8 @@ module ShellMessages = | "shutdown_request" -> ShutdownRequest (JsonConvert.DeserializeObject(messageJson)) | "shutdown_reply" -> ShutdownReply (JsonConvert.DeserializeObject(messageJson)) + + //Jupyter 4.x support, do we need to do anything with this? + | "comm_open" -> CommOpen (JsonConvert.DeserializeObject(messageJson)) + | _ -> failwith ("Unsupported messageType: " + messageType) \ No newline at end of file diff --git a/src/IfSharpConsole/Program.cs b/src/IfSharpConsole/Program.cs index bfc1d3a..3760510 100644 --- a/src/IfSharpConsole/Program.cs +++ b/src/IfSharpConsole/Program.cs @@ -1,4 +1,5 @@ using IfSharp.Kernel; +using System.Globalization; namespace IfSharpConsole { @@ -6,6 +7,8 @@ class Program { static void Main(string[] args) { + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; App.Start(args); } } From d401422c2077bb326d5eeabae518816000dbdbc5 Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Tue, 20 Oct 2015 13:35:20 +0200 Subject: [PATCH 02/20] Added git-excluded files --- kernel-spec/kernel.json | 5 +++++ kernel-spec/logo-32x32.png | Bin 0 -> 413 bytes kernel-spec/logo-64x64.png | Bin 0 -> 543 bytes 3 files changed, 5 insertions(+) create mode 100644 kernel-spec/kernel.json create mode 100644 kernel-spec/logo-32x32.png create mode 100644 kernel-spec/logo-64x64.png diff --git a/kernel-spec/kernel.json b/kernel-spec/kernel.json new file mode 100644 index 0000000..0f226a6 --- /dev/null +++ b/kernel-spec/kernel.json @@ -0,0 +1,5 @@ +{ + "display_name": "IFSharp", + "argv": ["mono", "%s", "{connection_file}"], + "language": "fsharp" +} diff --git a/kernel-spec/logo-32x32.png b/kernel-spec/logo-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..14879ed7ef87dc3955e6a0b19ccdfad4e6cbc637 GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI zppL5`%xHTp;v-Oyy~NYkmHj?D2d|W#4fm8s3=E7~o-U3d5r^MS-tWicC~&NPyVH`5 zpB>k%@z~Kdk9~u|6tT9JV=YV>8y@-8FlQ$(ZDsB36s+O)(#qmEd(-Dc#hrJ$92*n% zrxb18{yBgD%*F;FNOn)LT+a7fO5pTQ=Obyedxg_$dnIy}H;N=4-nmJZ@vMyW-;Q|w zZ;1=ElMb7HSo3Jk(;I7&rx=N6I-ZXC&YZw#(jaLd@>}}B?Q2?_pU;e96hE-MW`9HQ z^k&V9wbPa;{FME`bf&e}sDS^AO!KabOxN3fEa0>0jAOkgBfasun98IFf*C7QW;yaj zI(Qq3G0HB`uX>VndBxOM|2B4bCusc={qSzHt=qCK(`R05m*uix%yX@0J!a>pI`f{5 zS8T+yKeILVzI_;fbLy*uVyiQyuZ28f0fImFbqw#%`Wz6sop1{nkPM!#elF{r5}E+c Cm#OCf literal 0 HcmV?d00001 diff --git a/kernel-spec/logo-64x64.png b/kernel-spec/logo-64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..e2519a5835906cd881a5be4061e72d1d443bbb44 GIT binary patch literal 543 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=Y)RhkE)4%caKYZ?lYt_f1s;*b zKpj^>n9=rH#7CeYdx@v7EBk$R4qi#?s^7||7#JAWc)B=-RNQ(yW54%d2a)6ZueY%U z%7`2cRd*~5F3{TM`l0^Yag`k_yBGT@S-nWv=-PWa+~SpI?mNA`6W+5sP0D}wE;jDn z-s7wSP8^CYP@;n^QEOB1nUnuQcI%oI$*wz?X6dx)q+z^eI>U|SWzUTZ!X}GefBsYE zfcScLoB3xF))!bF@Ub!JZ0SACxO|#fLB_q0K@~RcOZKrHF#eq%7|rnE+|>%8r_)%)J2N7?Sol%6avs|WjQyE`nOUAHm1(!TL4Q{|djGov`3Ftjn)F|G-S zX8YjSuJh}h^5=+ip&?z&YJ0R9^snqnn23`;u3sZb%Ppyx3AEb}8W54mdKI;Vst0F{&Hi2wiq literal 0 HcmV?d00001 From 98d8ce867a1fe24d4168a588eedc8b6c77fef068 Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Tue, 20 Oct 2015 16:44:59 +0200 Subject: [PATCH 03/20] Added missing file --- IfSharp.sln | 5 +++-- ipython-profile/ipython_qtconsole_config.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 ipython-profile/ipython_qtconsole_config.py diff --git a/IfSharp.sln b/IfSharp.sln index 3e15958..78db946 100644 --- a/IfSharp.sln +++ b/IfSharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "IfSharp.Kernel", "src\IfSharp.Kernel\IfSharp.Kernel.fsproj", "{2FE619B3-4756-4285-B31F-232607F62D78}" EndProject @@ -51,6 +51,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ipython-profile", "ipython- ProjectSection(SolutionItems) = preProject ipython-profile\static\custom\ifsharp_logo.png = ipython-profile\static\custom\ifsharp_logo.png ipython-profile\ipython_config.py = ipython-profile\ipython_config.py + ipython-profile\ipython_qtconsole_config.py = ipython-profile\ipython_qtconsole_config.py ipython-profile\kernel.js = ipython-profile\kernel.js EndProjectSection EndProject @@ -134,10 +135,10 @@ Global GlobalSection(NestedProjects) = preSolution {A8428CDC-273B-434D-AAA2-0D0164E3D329} = {9D4EDE1C-AB08-4800-9A57-4689DA45B701} {E7CBA335-71DC-45BC-BB08-8837F866EDB9} = {9D4EDE1C-AB08-4800-9A57-4689DA45B701} - {F420A7BF-AF5F-4C69-99D3-C0DA09FA1F19} = {9D4EDE1C-AB08-4800-9A57-4689DA45B701} {52627028-50B5-427F-BDDB-9DEADB72E7D6} = {88BC26ED-4DC4-4035-AA6D-44CD2A160996} {45519D10-5973-41C3-A8D0-BCBF0008044D} = {F5A3E866-86FB-44AD-9ED1-DB65D6EB0058} {3AAFA64D-CBB6-488E-B395-6A1E7CB554CE} = {45519D10-5973-41C3-A8D0-BCBF0008044D} + {F420A7BF-AF5F-4C69-99D3-C0DA09FA1F19} = {9D4EDE1C-AB08-4800-9A57-4689DA45B701} {7B100429-EB1D-4D08-919F-5F9D6D148BFA} = {F420A7BF-AF5F-4C69-99D3-C0DA09FA1F19} EndGlobalSection EndGlobal diff --git a/ipython-profile/ipython_qtconsole_config.py b/ipython-profile/ipython_qtconsole_config.py new file mode 100644 index 0000000..decb547 --- /dev/null +++ b/ipython-profile/ipython_qtconsole_config.py @@ -0,0 +1,3 @@ +c = get_config() +c.IPythonWidget.execute_on_complete_input = False +c.FrontendWidget.lexer_class = 'pygments.lexers.FSharpLexer' From 62c71628da3c1fb61712c981a0b84a25e9b0ecb1 Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Tue, 20 Oct 2015 18:25:19 +0200 Subject: [PATCH 04/20] Implemented message signing --- ipython-profile/ipython_config.py | 2 -- src/IfSharp.Kernel/Kernel.fs | 26 ++++++++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ipython-profile/ipython_config.py b/ipython-profile/ipython_config.py index 56f1f0e..9189126 100644 --- a/ipython-profile/ipython_config.py +++ b/ipython-profile/ipython_config.py @@ -1,5 +1,3 @@ c = get_config() c.KernelManager.kernel_spec = [ "mono", r"%kexe", "{connection_file}"] -c.Session.key = b'' -c.Session.keyfile = '' c.NotebookApp.extra_static_paths = [ r"%kfolder" ] \ No newline at end of file diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index fd02a6a..a3da56e 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -7,6 +7,7 @@ open System.IO open System.Reflection open System.Text open System.Threading +open System.Security.Cryptography open FSharp.Charting @@ -65,6 +66,14 @@ type IfSharpKernel(connectionInformation : ConnectionInformation, ioSocket : Soc ser.Serialize(sw, obj) sw.ToString() + /// Sign a set of strings. + let hmac = new HMACSHA256(Encoding.UTF8.GetBytes(connectionInformation.key)) + let sign (parts:string list) : string = + ignore (hmac.Initialize()) + List.iter (fun (s:string) -> let bytes = Encoding.UTF8.GetBytes(s) in ignore(hmac.TransformBlock(bytes, 0, bytes.Length, null, 0))) parts + ignore (hmac.TransformFinalBlock(Array.zeroCreate 0, 0, 0)) + BitConverter.ToString(hmac.Hash).Replace("-", "").ToLower() + /// Constructs an 'envelope' from the specified socket let recvMessage (socket) = @@ -94,6 +103,9 @@ type IfSharpKernel(connectionInformation : ConnectionInformation, ioSocket : Soc let metaDataDict = deserializeDict (metadata) let content = ShellMessages.Deserialize (header.msg_type) (contentJson) + let calculated_signature = sign [headerJson; parentHeaderJson; metadata; contentJson] + if calculated_signature <> hmac then failwith("Wrong message signature") + lastMessage <- Some { Identifiers = idents |> Seq.toList; @@ -123,13 +135,19 @@ type IfSharpKernel(connectionInformation : ConnectionInformation, ioSocket : Soc for ident in envelope.Identifiers do socket <~| (encode ident) |> ignore + let header = serialize header + let parent_header = serialize envelope.Header + let meta = "{}" + let content = serialize content + let signature = sign [header; parent_header; meta; content] + socket <~| (encode "") - <~| (encode "") - <~| (encode (serialize header)) - <~| (encode (serialize envelope.Header)) + <~| (encode signature) + <~| (encode header) + <~| (encode parent_header) <~| (encode "{}") - <<| (encode (serialize content)) + <<| (encode content) /// Convenience method for sending the state of the kernel let sendState (envelope) (state) = From af8b6a568cc9f722497b72acecebd944a6d1c15a Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Tue, 20 Oct 2015 18:28:56 +0200 Subject: [PATCH 05/20] Proper handling of unsigned messages. --- src/IfSharp.Kernel/Kernel.fs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index a3da56e..5c84ed7 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -69,10 +69,11 @@ type IfSharpKernel(connectionInformation : ConnectionInformation, ioSocket : Soc /// Sign a set of strings. let hmac = new HMACSHA256(Encoding.UTF8.GetBytes(connectionInformation.key)) let sign (parts:string list) : string = - ignore (hmac.Initialize()) - List.iter (fun (s:string) -> let bytes = Encoding.UTF8.GetBytes(s) in ignore(hmac.TransformBlock(bytes, 0, bytes.Length, null, 0))) parts - ignore (hmac.TransformFinalBlock(Array.zeroCreate 0, 0, 0)) - BitConverter.ToString(hmac.Hash).Replace("-", "").ToLower() + if connectionInformation.key = "" then "" else + ignore (hmac.Initialize()) + List.iter (fun (s:string) -> let bytes = Encoding.UTF8.GetBytes(s) in ignore(hmac.TransformBlock(bytes, 0, bytes.Length, null, 0))) parts + ignore (hmac.TransformFinalBlock(Array.zeroCreate 0, 0, 0)) + BitConverter.ToString(hmac.Hash).Replace("-", "").ToLower() /// Constructs an 'envelope' from the specified socket let recvMessage (socket) = From 6db42429a1afaa228b0e5de2485d5939a0ee062b Mon Sep 17 00:00:00 2001 From: Niall Murphy Date: Tue, 20 Oct 2015 22:47:14 +0100 Subject: [PATCH 06/20] linux kernel spec paths corrected --- src/IfSharp.Kernel/App.fs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/IfSharp.Kernel/App.fs b/src/IfSharp.Kernel/App.fs index 701c286..33d923e 100644 --- a/src/IfSharp.Kernel/App.fs +++ b/src/IfSharp.Kernel/App.fs @@ -149,8 +149,15 @@ module App = let thisExecutable = Assembly.GetEntryAssembly().Location let userDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - let appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) - let jupyterDir = Path.Combine(appData, "Jupyter") + let appData = + match Environment.OSVersion.Platform with + | PlatformID.Win32Windows | PlatformID.Win32NT -> Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + | PlatformID.MacOSX -> Path.Combine(userDir, "Library") + | _ -> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) // PlatformID.Unix + let jupyterDir = + match Environment.OSVersion.Platform with + | PlatformID.Unix -> Path.Combine(appData, "jupyter") + | _ -> Path.Combine(appData, "Jupyter") let kernelsDir = Path.Combine(jupyterDir, "kernels") let kernelDir = Path.Combine(kernelsDir, "ifsharp") let staticDir = Path.Combine(kernelDir, "static") @@ -178,8 +185,7 @@ module App = let codeTemplate = IfSharpResources.ipython_config() let code = match Environment.OSVersion.Platform with - | PlatformID.Win32Windows -> codeTemplate.Replace("\"mono\",", "") - | PlatformID.Win32NT -> codeTemplate.Replace("\"mono\",", "") + | PlatformID.Win32Windows | PlatformID.Win32NT -> codeTemplate.Replace("\"mono\",", "") | _ -> codeTemplate let code = code.Replace("%kexe", thisExecutable) let code = code.Replace("%kfolder", staticDir) From ff83e690fbec7f651fd5fc0f73255b051c4a50ff Mon Sep 17 00:00:00 2001 From: Niall Murphy Date: Tue, 20 Oct 2015 23:21:03 +0100 Subject: [PATCH 07/20] remove old 0zmq comment --- src/IfSharp.Kernel/Kernel.fs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index e1f5cf4..7efc09e 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -165,16 +165,6 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = let content = serialize content let signature = sign [header; parent_header; meta; content] - (* - socket - <~| (encode "") - <~| (encode signature) - <~| (encode header) - <~| (encode parent_header) - <~| (encode "{}") - <<| (encode content) - *) - msg.Append(encode "") msg.Append(encode signature) msg.Append(encode (serialize header)) From 491edf0888fe5da799311bd0402d63885462a55a Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Wed, 21 Oct 2015 09:29:39 +0200 Subject: [PATCH 08/20] Fixed automerge mistake --- src/IfSharp.Kernel/Kernel.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index 7efc09e..5a9566f 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -167,10 +167,10 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = msg.Append(encode "") msg.Append(encode signature) - msg.Append(encode (serialize header)) - msg.Append(encode (serialize envelope.Header)) + msg.Append(encode header) + msg.Append(encode parent_header) msg.Append(encode "{}") - msg.Append(encode (serialize content)) + msg.Append(encode content) socket.SendMessage(msg) From 41b93bf2febb008b602c7792382372cee5d4888b Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Tue, 27 Oct 2015 16:33:38 +0100 Subject: [PATCH 09/20] Added InspectRequest dummy implementation --- src/IfSharp.Kernel/Kernel.fs | 5 +++++ src/IfSharp.Kernel/ShellMessages.fs | 32 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index 5a9566f..349d4d9 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -423,6 +423,10 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = // TODO: actually handle this () + let inspectRequest (msg : KernelMessage) (content : InspectRequest) = + // TODO: actually handle this + () + /// Loops forever receiving messages from the client and processing them let doShell() = @@ -448,6 +452,7 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = | ShutdownRequest(r) -> shutdownRequest msg r | HistoryRequest(r) -> historyRequest msg r | ObjectInfoRequest(r) -> objectInfoRequest msg r + | InspectRequest(r) -> inspectRequest msg r | _ -> logMessage (String.Format("Unknown content type. msg_type is `{0}`", msg.Header.msg_type)) with | ex -> handleException ex diff --git a/src/IfSharp.Kernel/ShellMessages.fs b/src/IfSharp.Kernel/ShellMessages.fs index ea52597..de11f12 100644 --- a/src/IfSharp.Kernel/ShellMessages.fs +++ b/src/IfSharp.Kernel/ShellMessages.fs @@ -95,6 +95,35 @@ type ObjectInfoRequest = detail_level: int; } +type InspectRequest = + { + // # The code context in which introspection is requested + // # this may be up to an entire multiline cell. + code: string; + + // # The cursor position within 'code' (in unicode characters) where inspection is requested + cursor_pos: int; + + // # The level of detail desired. In IPython, the default (0) is equivalent to typing + // # 'x?' at the prompt, 1 is equivalent to 'x??'. + // # The difference is up to kernels, but in IPython level 1 includes the source code + // # if available. + detail_level: int; + } + +type InspectReply = + { + // # 'ok' if the request succeeded or 'error', with error information as in all other replies. + status: string; + + // # found should be true if an object was found, false otherwise + found: bool; + + // # data can be empty if nothing is found + data: Dictionary; + metadata: Dictionary; + } + type ArgsSpec = { // # The names of all the arguments @@ -414,6 +443,8 @@ type ShellMessage = | ExecuteReplyError of ExecuteReplyError // intellisense + | InspectRequest of InspectRequest + | InspectReply of InspectReply | ObjectInfoRequest of ObjectInfoRequest | CompleteRequest of CompleteRequest | IntellisenseRequest of IntellisenseRequest @@ -471,6 +502,7 @@ module ShellMessages = | "execute_reply_error" -> ExecuteReplyError (JsonConvert.DeserializeObject(messageJson)) | "object_info_request" -> ObjectInfoRequest (JsonConvert.DeserializeObject(messageJson)) + | "inspect_request" -> InspectRequest (JsonConvert.DeserializeObject(messageJson)) | "complete_request" -> CompleteRequest (JsonConvert.DeserializeObject(messageJson)) | "complete_reply" -> CompleteReply (JsonConvert.DeserializeObject(messageJson)) From d134d243f8e999dc1e22ac158b131ec72daf077c Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Tue, 27 Oct 2015 16:39:48 +0100 Subject: [PATCH 10/20] Added dummy answer to inspect_request --- src/IfSharp.Kernel/Kernel.fs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index 349d4d9..f81f4d7 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -425,6 +425,8 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = let inspectRequest (msg : KernelMessage) (content : InspectRequest) = // TODO: actually handle this + let reply = { status = "ok"; found = false; data = Dictionary(); metadata = Dictionary() } + sendMessage shellSocket msg "inspect_reply" reply () /// Loops forever receiving messages from the client and processing them From 1e7d25fdf79bd8a74489c980b40a8aa606587aa5 Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Wed, 28 Oct 2015 08:04:21 +0100 Subject: [PATCH 11/20] Wrapped logging in an exception handler --- src/IfSharp.Kernel/Kernel.fs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index f81f4d7..4eaa42c 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -59,8 +59,9 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = |> Seq.filter (fun x -> x <> "") |> Seq.map (fun x -> String.Format("{0:yyyy-MM-dd HH:mm:ss} - {1}", DateTime.Now, x)) |> Seq.toArray - - File.AppendAllLines(fileName, messages) + try + File.AppendAllLines(fileName, messages) + with _ -> () /// Logs the exception to the specified file name let handleException (ex : exn) = From 479c61805efa26d1d10d444c6f7cad6d7693a53f Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Wed, 28 Oct 2015 08:59:47 +0100 Subject: [PATCH 12/20] Added GenericChartsWithSize, for outputting multiple charts. --- src/IfSharp.Kernel/Printers.fs | 21 +++++++++++++++++++++ src/IfSharp.Kernel/Util.fs | 11 ++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/IfSharp.Kernel/Printers.fs b/src/IfSharp.Kernel/Printers.fs index e0cf05a..3d770ea 100644 --- a/src/IfSharp.Kernel/Printers.fs +++ b/src/IfSharp.Kernel/Printers.fs @@ -3,6 +3,9 @@ open System open System.Text open System.Web +open System.Drawing +open System.Drawing.Imaging +open System.IO open FSharp.Charting module Printers = @@ -45,6 +48,24 @@ module Printers = { ContentType = "image/png"; Data = x.Chart.ToPng(x.Size) } ) + addDisplayPrinter(fun (x:GenericChartsWithSize) -> + let count = x.Charts.Length + let (width, height) = x.Size + let totalWidth = if count = 1 then width else width * 2 + let totalHeight = (count+1) / 2 * height + let finalBitmap = new Bitmap(totalWidth, totalHeight) + let finalGraphics = Graphics.FromImage(finalBitmap) + let copy i (chart:ChartTypes.GenericChart) = + let img = chart.ToPng(x.Size) + let bitmap = new Bitmap(new MemoryStream(img)) + finalGraphics.DrawImage(bitmap, i % 2 * width, i / 2 * height) + List.iteri copy x.Charts; + finalGraphics.Dispose(); + let ms = new MemoryStream() + finalBitmap.Save(ms, ImageFormat.Png); + { ContentType = "image/png"; Data = ms.ToArray() } + ) + // add table printer addDisplayPrinter(fun (x:TableOutput) -> let sb = StringBuilder() diff --git a/src/IfSharp.Kernel/Util.fs b/src/IfSharp.Kernel/Util.fs index 1933bdf..9131475 100644 --- a/src/IfSharp.Kernel/Util.fs +++ b/src/IfSharp.Kernel/Util.fs @@ -42,6 +42,12 @@ type GenericChartWithSize = Size: int * int; } +type GenericChartsWithSize = + { + Charts: ChartTypes.GenericChart list; + Size: int * int; + } + [] module ExtensionMethods = @@ -155,4 +161,7 @@ type Util = /// Loads a local image from disk and wraps a BinaryOutput around the image data. static member Image (fileName:string) = - Util.Image (File.ReadAllBytes(fileName)) \ No newline at end of file + Util.Image (File.ReadAllBytes(fileName)) + + static member MultipleCharts (charts: ChartTypes.GenericChart list) (size:int*int) = + { Charts = charts; Size = size } \ No newline at end of file From d91f800db86ccfa58f89682abb527359683ce0cf Mon Sep 17 00:00:00 2001 From: Neil Dalchau Date: Fri, 30 Oct 2015 10:41:46 +0000 Subject: [PATCH 13/20] Extending MultiplePlots to use different numbers of columns --- src/IfSharp.Kernel/IfSharp.Kernel.fsproj | 3 +-- src/IfSharp.Kernel/Printers.fs | 7 ++++--- src/IfSharp.Kernel/Util.fs | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj index 2553332..1ed5ff2 100644 --- a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj +++ b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj @@ -99,8 +99,7 @@ - ..\..\packages\FSharp.Charting.0.90.5\lib\net40\FSharp.Charting.dll - True + ..\..\..\..\FSharp.Charting\bin\FSharp.Charting.dll ..\..\packages\FSharp.Compiler.Service.0.0.81\lib\net45\FSharp.Compiler.Service.dll diff --git a/src/IfSharp.Kernel/Printers.fs b/src/IfSharp.Kernel/Printers.fs index 3d770ea..3a3f9a6 100644 --- a/src/IfSharp.Kernel/Printers.fs +++ b/src/IfSharp.Kernel/Printers.fs @@ -51,14 +51,15 @@ module Printers = addDisplayPrinter(fun (x:GenericChartsWithSize) -> let count = x.Charts.Length let (width, height) = x.Size - let totalWidth = if count = 1 then width else width * 2 - let totalHeight = (count+1) / 2 * height + let totalWidth = if count = 1 then width else width * x.Columns + let numRows = int (Math.Ceiling (float count / float x.Columns)) + let totalHeight = numRows * height let finalBitmap = new Bitmap(totalWidth, totalHeight) let finalGraphics = Graphics.FromImage(finalBitmap) let copy i (chart:ChartTypes.GenericChart) = let img = chart.ToPng(x.Size) let bitmap = new Bitmap(new MemoryStream(img)) - finalGraphics.DrawImage(bitmap, i % 2 * width, i / 2 * height) + finalGraphics.DrawImage(bitmap, i % x.Columns * width, i / x.Columns * height) List.iteri copy x.Charts; finalGraphics.Dispose(); let ms = new MemoryStream() diff --git a/src/IfSharp.Kernel/Util.fs b/src/IfSharp.Kernel/Util.fs index 9131475..94153c1 100644 --- a/src/IfSharp.Kernel/Util.fs +++ b/src/IfSharp.Kernel/Util.fs @@ -46,6 +46,7 @@ type GenericChartsWithSize = { Charts: ChartTypes.GenericChart list; Size: int * int; + Columns: int; } [] @@ -163,5 +164,5 @@ type Util = static member Image (fileName:string) = Util.Image (File.ReadAllBytes(fileName)) - static member MultipleCharts (charts: ChartTypes.GenericChart list) (size:int*int) = - { Charts = charts; Size = size } \ No newline at end of file + static member MultipleCharts (charts: ChartTypes.GenericChart list) (size:int*int) (cols:int) = + { Charts = charts; Size = size; Columns = cols } \ No newline at end of file From bfedd74b8f8b9f766269509eff031c8c8e6407e4 Mon Sep 17 00:00:00 2001 From: Neil Dalchau Date: Wed, 4 Nov 2015 15:12:20 +0000 Subject: [PATCH 14/20] Reverting to packages version of FSharp.Charting. --- src/IfSharp.Kernel/IfSharp.Kernel.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj index 1ed5ff2..71147ed 100644 --- a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj +++ b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj @@ -99,7 +99,7 @@ - ..\..\..\..\FSharp.Charting\bin\FSharp.Charting.dll + ..\..\packages\FSharp.Charting.0.90.5\lib\net40\FSharp.Charting.dll ..\..\packages\FSharp.Compiler.Service.0.0.81\lib\net45\FSharp.Compiler.Service.dll From 6f8b84d650807b44a5e929865a0c6864fae74872 Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Wed, 4 Nov 2015 17:13:57 +0100 Subject: [PATCH 15/20] Added the ability to prepare temporary files to serve. --- ipython-profile/ipython_config.py | 2 +- src/IfSharp.Kernel/App.fs | 26 ++++++++++---------------- src/IfSharp.Kernel/Util.fs | 30 ++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/ipython-profile/ipython_config.py b/ipython-profile/ipython_config.py index 9189126..1c09ea8 100644 --- a/ipython-profile/ipython_config.py +++ b/ipython-profile/ipython_config.py @@ -1,3 +1,3 @@ c = get_config() c.KernelManager.kernel_spec = [ "mono", r"%kexe", "{connection_file}"] -c.NotebookApp.extra_static_paths = [ r"%kfolder" ] \ No newline at end of file +c.NotebookApp.extra_static_paths = [ r"%kfolder", r"%ktemp" ] \ No newline at end of file diff --git a/src/IfSharp.Kernel/App.fs b/src/IfSharp.Kernel/App.fs index adaea2b..17242ef 100644 --- a/src/IfSharp.Kernel/App.fs +++ b/src/IfSharp.Kernel/App.fs @@ -142,34 +142,23 @@ module App = // add to the payload Kernel.Value.AddPayload(text.ToString()) - /// Installs the ifsharp files if they do not exist, then starts ipython with the ifsharp profile + /// Installs the ifsharp files if they do not exist, then starts jupyter with the ifsharp profile let InstallAndStart(forceInstall) = let thisExecutable = Assembly.GetEntryAssembly().Location let userDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - let appData = - match Environment.OSVersion.Platform with - | PlatformID.Win32Windows | PlatformID.Win32NT -> Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) - | PlatformID.MacOSX -> Path.Combine(userDir, "Library") - | _ -> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) // PlatformID.Unix - let jupyterDir = - match Environment.OSVersion.Platform with - | PlatformID.Unix -> Path.Combine(appData, "jupyter") - | _ -> Path.Combine(appData, "Jupyter") - let kernelsDir = Path.Combine(jupyterDir, "kernels") - let kernelDir = Path.Combine(kernelsDir, "ifsharp") + let kernelDir = InternalUtil.KernelDir let staticDir = Path.Combine(kernelDir, "static") + let tempDir = InternalUtil.KernelDir let customDir = Path.Combine(staticDir, "custom") let createDir(str) = if Directory.Exists(str) = false then Directory.CreateDirectory(str) |> ignore - createDir appData - createDir jupyterDir - createDir kernelsDir createDir kernelDir createDir staticDir + createDir tempDir createDir customDir let configFile = Path.Combine(kernelDir, "ipython_config.py") @@ -187,6 +176,7 @@ module App = | _ -> codeTemplate let code = code.Replace("%kexe", thisExecutable) let code = code.Replace("%kfolder", staticDir) + let code = code.Replace("%ktemp", tempDir) printfn "Saving custom config file [%s]" configFile File.WriteAllText(configFile, code) @@ -260,11 +250,15 @@ module App = InstallAndStart(true) else + // Clear the temporary folder + try + if Directory.Exists(InternalUtil.TempDir) then Directory.Delete(InternalUtil.TempDir, true) + Directory.CreateDirectory(InternalUtil.TempDir) |> ignore; + with exc -> Console.Out.Write(exc.ToString()) // adds the default display printers Printers.addDefaultDisplayPrinters() - // get connection information let fileName = args.[0] let json = File.ReadAllText(fileName) diff --git a/src/IfSharp.Kernel/Util.fs b/src/IfSharp.Kernel/Util.fs index 94153c1..8206757 100644 --- a/src/IfSharp.Kernel/Util.fs +++ b/src/IfSharp.Kernel/Util.fs @@ -49,6 +49,25 @@ type GenericChartsWithSize = Columns: int; } +module InternalUtil = + let KernelDir = + let thisExecutable = System.Reflection.Assembly.GetEntryAssembly().Location + let userDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + let appData = + match Environment.OSVersion.Platform with + | PlatformID.Win32Windows | PlatformID.Win32NT -> Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + | PlatformID.MacOSX -> Path.Combine(userDir, "Library") + | _ -> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) // PlatformID.Unix + let jupyterDir = + match Environment.OSVersion.Platform with + | PlatformID.Unix -> Path.Combine(appData, "jupyter") + | _ -> Path.Combine(appData, "Jupyter") + let kernelsDir = Path.Combine(jupyterDir, "kernels") + let kernelDir = Path.Combine(kernelsDir, "ifsharp") + kernelDir + + let TempDir = Path.Combine(KernelDir, "temp"); + [] module ExtensionMethods = @@ -152,7 +171,6 @@ type Util = stream.CopyTo(mstream) { ContentType = res.ContentType; Data = mstream.ToArray() } - /// Wraps a BinaryOutput around image bytes with the specified content-type static member Image (bytes:seq, ?contentType:string) = { @@ -165,4 +183,12 @@ type Util = Util.Image (File.ReadAllBytes(fileName)) static member MultipleCharts (charts: ChartTypes.GenericChart list) (size:int*int) (cols:int) = - { Charts = charts; Size = size; Columns = cols } \ No newline at end of file + { Charts = charts; Size = size; Columns = cols } + + static member CreatePublicFile (name:string) (content:byte[]) = + try + let path = Path.Combine(InternalUtil.TempDir,name) + File.WriteAllBytes(path, content) + "/static/temp/"+name + with exc -> + exc.ToString() \ No newline at end of file From 6a9130fcad2cd9ccd528b4daaaaa228ff5ef08a0 Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Wed, 4 Nov 2015 18:08:08 +0100 Subject: [PATCH 16/20] Added some helpers to allow arranging multiple images in an output. --- src/IfSharp.Kernel/Util.fs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/IfSharp.Kernel/Util.fs b/src/IfSharp.Kernel/Util.fs index 8206757..d0215b2 100644 --- a/src/IfSharp.Kernel/Util.fs +++ b/src/IfSharp.Kernel/Util.fs @@ -113,6 +113,12 @@ module ExtensionMethods = actualChart.SaveImage(ms, ImageFormat.Png) ms.ToArray() + member self.ToData(?size) = + let bytes = match size with Some size -> self.ToPng(size) | _ -> self.ToPng() + let base64 = Convert.ToBase64String(bytes) + let data = "data:image/png;base64,"+base64 + data + type FSharp.Charting.Chart with /// Wraps a GenericChartWithSize around the GenericChart @@ -178,6 +184,11 @@ type Util = Data = bytes; } + static member Base64 (bytes:seq, contentType:string) = + let base64 = Convert.ToBase64String(Array.ofSeq bytes) + let data = "data:"+contentType+";base64,"+base64 + data + /// Loads a local image from disk and wraps a BinaryOutput around the image data. static member Image (fileName:string) = Util.Image (File.ReadAllBytes(fileName)) @@ -191,4 +202,4 @@ type Util = File.WriteAllBytes(path, content) "/static/temp/"+name with exc -> - exc.ToString() \ No newline at end of file + exc.ToString() \ No newline at end of file From 93dd982d75457a9b947aaec60268c2281f316314 Mon Sep 17 00:00:00 2001 From: Filippo Polo Date: Thu, 5 Nov 2015 12:53:21 +0100 Subject: [PATCH 17/20] Added SVG moving and merging functions. --- ipython-profile/ipython_config.py | 2 +- src/IfSharp.Kernel/App.fs | 8 ++--- src/IfSharp.Kernel/IfSharp.Kernel.fsproj | 1 + src/IfSharp.Kernel/Util.fs | 46 ++++++++++++++++++++++-- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/ipython-profile/ipython_config.py b/ipython-profile/ipython_config.py index 1c09ea8..c399197 100644 --- a/ipython-profile/ipython_config.py +++ b/ipython-profile/ipython_config.py @@ -1,3 +1,3 @@ c = get_config() c.KernelManager.kernel_spec = [ "mono", r"%kexe", "{connection_file}"] -c.NotebookApp.extra_static_paths = [ r"%kfolder", r"%ktemp" ] \ No newline at end of file +c.NotebookApp.extra_static_paths = [ r"%kstatic" ] \ No newline at end of file diff --git a/src/IfSharp.Kernel/App.fs b/src/IfSharp.Kernel/App.fs index 17242ef..70c4811 100644 --- a/src/IfSharp.Kernel/App.fs +++ b/src/IfSharp.Kernel/App.fs @@ -148,8 +148,8 @@ module App = let thisExecutable = Assembly.GetEntryAssembly().Location let userDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); let kernelDir = InternalUtil.KernelDir - let staticDir = Path.Combine(kernelDir, "static") - let tempDir = InternalUtil.KernelDir + let staticDir = InternalUtil.StaticDir + let tempDir = InternalUtil.TempDir let customDir = Path.Combine(staticDir, "custom") let createDir(str) = @@ -175,8 +175,7 @@ module App = | PlatformID.Win32Windows | PlatformID.Win32NT -> codeTemplate.Replace("\"mono\",", "") | _ -> codeTemplate let code = code.Replace("%kexe", thisExecutable) - let code = code.Replace("%kfolder", staticDir) - let code = code.Replace("%ktemp", tempDir) + let code = code.Replace("%kstatic", staticDir) printfn "Saving custom config file [%s]" configFile File.WriteAllText(configFile, code) @@ -253,7 +252,6 @@ module App = // Clear the temporary folder try if Directory.Exists(InternalUtil.TempDir) then Directory.Delete(InternalUtil.TempDir, true) - Directory.CreateDirectory(InternalUtil.TempDir) |> ignore; with exc -> Console.Out.Write(exc.ToString()) // adds the default display printers diff --git a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj index 71147ed..8011468 100644 --- a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj +++ b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj @@ -127,6 +127,7 @@ +