From 5975e45337a87c95d6c53059efe997ef79eb8bfd Mon Sep 17 00:00:00 2001 From: bryphe Date: Fri, 22 Mar 2019 07:39:46 -0700 Subject: [PATCH 01/20] Initial integration --- src/editor/bin/Oni2.re | 1 + src/textmate_service/package.json | 1 + src/textmate_service/yarn.lock | 24 +++++++++++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index 873832116f..0302c52742 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -35,6 +35,7 @@ let init = app => { ...Window.defaultCreateOptions, maximized: false, icon: Some("logo.png"), + vsync: false, }, app, "Oni2", diff --git a/src/textmate_service/package.json b/src/textmate_service/package.json index 32a7180b7b..52b8b763f9 100644 --- a/src/textmate_service/package.json +++ b/src/textmate_service/package.json @@ -19,6 +19,7 @@ "@types/node": "^11.9.5", "typescript": "^3.3.3333", "vscode-jsonrpc": "^4.0.0", + "vscode-exthost": "1.33.3", "jest": "*", "@types/jest": "*" } diff --git a/src/textmate_service/yarn.lock b/src/textmate_service/yarn.lock index 9502611050..04617cc48d 100644 --- a/src/textmate_service/yarn.lock +++ b/src/textmate_service/yarn.lock @@ -1063,6 +1063,11 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw== +graceful-fs@4.1.11: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" @@ -1171,6 +1176,13 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + iconv-lite@0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -3251,7 +3263,17 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vscode-jsonrpc@^4.0.0: +vscode-exthost@1.33.3: + version "1.33.3" + resolved "https://registry.yarnpkg.com/vscode-exthost/-/vscode-exthost-1.33.3.tgz#4f3e24f028a7b0fc9c50adeed041ab97dab4d444" + integrity sha512-OdCtAA+NfevGzmwIAEazV6TPBZRQS9wcIBz+CaSB1nBY8tfGK7Ly6hZeJ4Cf4sgmjzEqSAGzy+QjENNOXhck+A== + dependencies: + graceful-fs "4.1.11" + iconv-lite "0.4.23" + semver "^5.5.0" + vscode-jsonrpc "4.0.0" + +vscode-jsonrpc@4.0.0, vscode-jsonrpc@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== From fcd22fd98dd0b680c5ad1584c86acb1411ff0c68 Mon Sep 17 00:00:00 2001 From: bryphe Date: Fri, 22 Mar 2019 07:40:17 -0700 Subject: [PATCH 02/20] Revert vsync change --- src/editor/bin/Oni2.re | 1 - 1 file changed, 1 deletion(-) diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index 0302c52742..873832116f 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -35,7 +35,6 @@ let init = app => { ...Window.defaultCreateOptions, maximized: false, icon: Some("logo.png"), - vsync: false, }, app, "Oni2", From ecddc735c7241a803f702d9c4bfc0de3a7bd7381 Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 07:19:38 -0700 Subject: [PATCH 03/20] Start adding extension host client Reason API --- src/editor/Core/Setup.re | 5 +++ src/editor/Extensions/ExtensionHostClient.re | 46 ++++++++++++++++++++ src/editor/Extensions/NodeProcess.re | 7 ++- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/editor/Extensions/ExtensionHostClient.re diff --git a/src/editor/Core/Setup.re b/src/editor/Core/Setup.re index bb7668524c..e408783d40 100644 --- a/src/editor/Core/Setup.re +++ b/src/editor/Core/Setup.re @@ -3,6 +3,7 @@ * * Runtime configuration of dependencies */ +open Rench; [@deriving (show, yojson({strict: false, exn: true}))] type t = { @@ -27,3 +28,7 @@ let ofFile = filePath => Yojson.Safe.from_file(filePath) |> of_yojson_exn; let init = () => Revery.Environment.getExecutingDirectory() ++ "setup.json" |> ofFile; + +let getExtensionHostPath = (setup: t) => { + Path.join(setup.textmateServicePath, "node_modules/vscode-exthost/out/bootstrap-fork.js"); +}; diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re new file mode 100644 index 0000000000..8509912382 --- /dev/null +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -0,0 +1,46 @@ +/* + * ExtensionHostClient.re + * + * This is a client-side API for integrating with our VSCode extension host API. + * + */ + +module StartupInfo { + type t; +} + +open Oni_Core; +open Rench; + +let getPathToExtensionHostScript = (setup: Setup.t) => { + Path.join(Setup.getExtensionHostPath(setup), "out/) +}; + +let emptyJsonValue = `Assoc([]); + +let start = + ( + setup: Setup.t, + ) => { + + let args = "[--type=extensionHost"]; + let process = NodeProcess.start(~args, setup, getPathToExtensionHostScript(setup));; + + + let onNotification = (n: Notification.t, _) => { + switch (n.method, n.params) { + | _ => print_endline("[Extension Host Client] Unknown message: " ++ n.method); + }; + }; + + let onRequest = (_, _) => Ok(emptyJsonValue); + + let rpc = + Rpc.start( + ~onNotification, + ~onRequest, + ~onClose=onClosed, + process.stdout, + process.stdin, + ); +}; diff --git a/src/editor/Extensions/NodeProcess.re b/src/editor/Extensions/NodeProcess.re index 9579f22545..5718abc472 100644 --- a/src/editor/Extensions/NodeProcess.re +++ b/src/editor/Extensions/NodeProcess.re @@ -12,14 +12,17 @@ type t = { stdin: out_channel, }; -let start = (setup: Setup.t, scriptPath: string) => { +let start = (~args=[], setup: Setup.t, scriptPath: string) => { let (pstdin, stdin) = Unix.pipe(); let (stdout, pstdout) = Unix.pipe(); + let args = [setup.nodePath, scriptPath, ...args]) + | Array.of_list; + let pid = Unix.create_process_env( setup.nodePath, - [|setup.nodePath, scriptPath|], + args, Unix.environment(), pstdin, pstdout, From 1ed187fc14707e35998765862b71c5e00ac31519 Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 07:26:47 -0700 Subject: [PATCH 04/20] Initial ExtensionHost client start-up --- src/editor/Extensions/ExtensionHostClient.re | 22 +++++++++++++------- src/editor/Extensions/NodeProcess.re | 4 ++-- src/editor/Extensions/Oni_Extensions.re | 1 + src/editor/bin/Oni2.re | 5 +++++ 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index 8509912382..bccc3e00d5 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -5,26 +5,32 @@ * */ -module StartupInfo { - type t; -} - open Oni_Core; +open Reason_jsonrpc; open Rench; +type t = { + process: NodeProcess.t, + rpc: Rpc.t, +} + let getPathToExtensionHostScript = (setup: Setup.t) => { - Path.join(Setup.getExtensionHostPath(setup), "out/) + Path.join(Setup.getExtensionHostPath(setup), "out/bootstrap-fork.js"); }; let emptyJsonValue = `Assoc([]); +type simpleCallback = unit => unit; +let defaultCallback: simpleCallback = () => (); + let start = ( + ~onClosed=defaultCallback, setup: Setup.t, ) => { - let args = "[--type=extensionHost"]; - let process = NodeProcess.start(~args, setup, getPathToExtensionHostScript(setup));; + let args = ["--type=extensionHost"]; + let process = NodeProcess.start(~args, setup, getPathToExtensionHostScript(setup)); let onNotification = (n: Notification.t, _) => { @@ -43,4 +49,6 @@ let start = process.stdout, process.stdin, ); + + {process, rpc} }; diff --git a/src/editor/Extensions/NodeProcess.re b/src/editor/Extensions/NodeProcess.re index 5718abc472..0c22a65cde 100644 --- a/src/editor/Extensions/NodeProcess.re +++ b/src/editor/Extensions/NodeProcess.re @@ -16,8 +16,8 @@ let start = (~args=[], setup: Setup.t, scriptPath: string) => { let (pstdin, stdin) = Unix.pipe(); let (stdout, pstdout) = Unix.pipe(); - let args = [setup.nodePath, scriptPath, ...args]) - | Array.of_list; + let args = [setup.nodePath, scriptPath, ...args] + |> Array.of_list; let pid = Unix.create_process_env( diff --git a/src/editor/Extensions/Oni_Extensions.re b/src/editor/Extensions/Oni_Extensions.re index 2129802264..3fff74ecf7 100644 --- a/src/editor/Extensions/Oni_Extensions.re +++ b/src/editor/Extensions/Oni_Extensions.re @@ -7,6 +7,7 @@ module ColorMap = ColorMap; module ColorizedToken = ColorizedToken; module ExtensionContributions = ExtensionContributions; +module ExtensionHostClient = ExtensionHostClient; module ExtensionManifest = ExtensionManifest; module ExtensionScanner = ExtensionScanner; module TextmateClient = TextmateClient; diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index 873832116f..bb99774ac3 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -94,6 +94,11 @@ let init = app => { grammars, ); + let extHostClient = + Extensions.ExtensionHostClient.start( + setup + ); + Extensions.TextmateClient.setTheme(tmClient, defaultThemePath); let render = () => { From f897ecfab628d5b684808c804dbbaec51ecb739a Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 07:41:59 -0700 Subject: [PATCH 05/20] Get extension host running --- scripts/bootstrap.js | 3 +++ src/editor/Core/Setup.re | 7 ++----- src/editor/Extensions/ExtensionHostClient.re | 11 ++++------- src/editor/Extensions/NodeProcess.re | 8 ++++++-- src/editor/bin/Oni2.re | 1 + 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index 6475a222f7..8ba459f11d 100644 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -13,6 +13,7 @@ const isLinux = !isMac && !isWindows; let nodePath; let textMateServicePath = path.join(rootDir, "src", "textmate_service", "lib", "src", "index.js"); +let extensionHostPath = path.join(rootDir, "src", "textmate_service", "node_modules", "vscode-exthost", "out", "bootstrap-fork.js"); let extensionsPath = path.join(rootDir, "extensions"); let neovimPath; let configurationPath = path.join(configPath, "configuration.json"); @@ -23,6 +24,7 @@ const getCygwinPath = (inputPath) => { return inputPath.replace(/\\/g, "/") } if (isWindows) { nodePath = getCygwinPath(path.join(vendorPath, "node-v10.15.1", "win-x64", "node.exe")); textMateServicePath = getCygwinPath(textMateServicePath); + extensionHostPath = getCygwinPath(extensionHostPath); extensionsPath = getCygwinPath(extensionsPath); neovimPath = getCygwinPath(path.join(vendorPath, "neovim-0.3.3", "nvim-win64", "bin", "nvim.exe")); configurationPath = getCygwinPath(configurationPath); @@ -44,6 +46,7 @@ const config = { configuration: configurationPath, textmateService: textMateServicePath, bundledExtensions: extensionsPath, + extensionHost: extensionHostPath, keybindings: keybindingsPath, } const oniConfig = JSON.stringify(config) diff --git a/src/editor/Core/Setup.re b/src/editor/Core/Setup.re index e408783d40..05f4c72461 100644 --- a/src/editor/Core/Setup.re +++ b/src/editor/Core/Setup.re @@ -3,7 +3,6 @@ * * Runtime configuration of dependencies */ -open Rench; [@deriving (show, yojson({strict: false, exn: true}))] type t = { @@ -15,6 +14,8 @@ type t = { textmateServicePath: string, [@key "bundledExtensions"] bundledExtensionsPath: string, + [@key "extensionHost"] + extensionHostPath: string, [@key "configuration"] configPath: string, [@key "keybindings"] @@ -28,7 +29,3 @@ let ofFile = filePath => Yojson.Safe.from_file(filePath) |> of_yojson_exn; let init = () => Revery.Environment.getExecutingDirectory() ++ "setup.json" |> ofFile; - -let getExtensionHostPath = (setup: t) => { - Path.join(setup.textmateServicePath, "node_modules/vscode-exthost/out/bootstrap-fork.js"); -}; diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index bccc3e00d5..5b29082ac3 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -7,17 +7,12 @@ open Oni_Core; open Reason_jsonrpc; -open Rench; type t = { process: NodeProcess.t, rpc: Rpc.t, } -let getPathToExtensionHostScript = (setup: Setup.t) => { - Path.join(Setup.getExtensionHostPath(setup), "out/bootstrap-fork.js"); -}; - let emptyJsonValue = `Assoc([]); type simpleCallback = unit => unit; @@ -30,8 +25,8 @@ let start = ) => { let args = ["--type=extensionHost"]; - let process = NodeProcess.start(~args, setup, getPathToExtensionHostScript(setup)); - + let env = ["AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess"]; + let process = NodeProcess.start(~args, ~env, setup, setup.extensionHostPath); let onNotification = (n: Notification.t, _) => { switch (n.method, n.params) { @@ -52,3 +47,5 @@ let start = {process, rpc} }; + +let pump = (v: t) => Rpc.pump(v.rpc); diff --git a/src/editor/Extensions/NodeProcess.re b/src/editor/Extensions/NodeProcess.re index 0c22a65cde..51a836c0cb 100644 --- a/src/editor/Extensions/NodeProcess.re +++ b/src/editor/Extensions/NodeProcess.re @@ -12,18 +12,22 @@ type t = { stdin: out_channel, }; -let start = (~args=[], setup: Setup.t, scriptPath: string) => { +let start = (~args=[], ~env=[], setup: Setup.t, scriptPath: string) => { let (pstdin, stdin) = Unix.pipe(); let (stdout, pstdout) = Unix.pipe(); let args = [setup.nodePath, scriptPath, ...args] |> Array.of_list; + let env = env + |> Array.of_list + |> Array.append(Unix.environment()); + let pid = Unix.create_process_env( setup.nodePath, args, - Unix.environment(), + env, pstdin, pstdout, Unix.stderr, diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index bb99774ac3..345ab1be81 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -207,6 +207,7 @@ let init = app => { _ => { nvimApi.pump(); Extensions.TextmateClient.pump(tmClient); + Extensions.ExtensionHostClient.pump(extHostClient); }, Seconds(0.), ); From ceb832c0227a9003d1c421632005863af4ba633b Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 08:34:17 -0700 Subject: [PATCH 06/20] Hook up entry point to process messages --- src/editor/Extensions/ExtensionHostClient.re | 100 +++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index 5b29082ac3..a2d8e38c2e 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -7,6 +7,7 @@ open Oni_Core; open Reason_jsonrpc; +/* open Revery; */ type t = { process: NodeProcess.t, @@ -18,8 +19,85 @@ let emptyJsonValue = `Assoc([]); type simpleCallback = unit => unit; let defaultCallback: simpleCallback = () => (); +module Protocol { + + module MessageTypes { + let initialized = 0; + let ready = 1; + let initData = 2; + let terminate = 3; + }; + + module LogLevel { + let trace = 0; + let debug = 1; + let info = 2; + let warning = 3; + let error = 4; + let critical = 5; + let off = 6; + }; + + module Environment { + type t = { + /* isExtensionDevelopmentDebug: bool, */ + appRootPath: string, + appSettingsHomePath: string, + /* extensionDevelopmentLocationPath: string, */ + /* extensionTestsLocationPath: string, */ + globalStorageHomePath: string, + }; + + let create = (~appRootPath, ~appSettingsHomePath, ~globalStorageHomePath, ()) => { + appRootPath, + appSettingsHomePath, + globalStorageHomePath, + }; + }; + +/* module InitData { */ +/* [@deriving (show, yojson({strict: false, exn: true}))] */ +/* type t = { */ +/* parentPid: int, */ +/* environment: Environment.t, */ +/* logLevel: int, */ +/* logsLocationPath: string, */ +/* autoStart: bool, */ +/* }; */ +/* }; */ + + + module Notification { + + exception NotificationParseException(string); + + type t = { + msgType: int, + reqId: int, + payload: Yojson.Safe.json, + }; + + let of_yojson = (json: Yojson.Safe.json) => { + switch (json) { + | (`Assoc([ + ("type", `Int(t)), + ("reqId", `Int(reqId)), + ("payload", payload), + ])) => { + { msgType: t, reqId, payload} ; + } + | _ => raise(NotificationParseException("Unable to parse: " ++ Yojson.Safe.to_string(json))); + } + }; + }; +} + +type messageHandler = (int, Yojson.Safe.json) => result(option(Yojson.Safe.json), string); +let defaultMessageHandler = (_, _) => Ok(None); + let start = ( + ~onMessage=defaultMessageHandler, ~onClosed=defaultCallback, setup: Setup.t, ) => { @@ -28,8 +106,30 @@ let start = let env = ["AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess"]; let process = NodeProcess.start(~args, ~env, setup, setup.extensionHostPath); + let handleMessage = (id: int, _reqId: int, payload: Yojson.Safe.json) => { + + switch(onMessage(id, payload)) { + | Ok(None) => () + | Ok(Some(_)) => { + /* TODO: Send response */ + (); + } + | Error(_) => { + /* TODO: Send error */ + (); + } + }; + } + let onNotification = (n: Notification.t, _) => { switch (n.method, n.params) { + | ("host/msg", json) => { + open Protocol.Notification; + print_endline("[Extension Host Client] Unknown message: " ++ n.method); + print_endline ("JSON: " ++ Yojson.Safe.to_string(json)); + let parsedMessage = Protocol.Notification.of_yojson(json); + handleMessage(parsedMessage.msgType, parsedMessage.reqId, parsedMessage.payload); + } | _ => print_endline("[Extension Host Client] Unknown message: " ++ n.method); }; }; From 1213055498766ba3b4e6a53647771e764ca79745 Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 08:56:10 -0700 Subject: [PATCH 07/20] Add basic test case to verify we get 'Ready' message from extension host --- src/editor/Extensions/ExtensionHostClient.re | 4 ++- test/editor/Core/Oni_Core_Test.re | 2 ++ test/editor/Core/SetupTests.re | 5 ++- test/editor/Extensions/ExtensionClientTest.re | 33 +++++++++++++++++++ .../Extensions/TextmateTokenizerTests.re | 10 ++++-- test/editor/OniUnitTestRunner.re | 2 ++ test/editor/dune | 1 + 7 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 test/editor/Core/Oni_Core_Test.re create mode 100644 test/editor/Extensions/ExtensionClientTest.re diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index a2d8e38c2e..9c4ce47c41 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -21,7 +21,7 @@ let defaultCallback: simpleCallback = () => (); module Protocol { - module MessageTypes { + module MessageType { let initialized = 0; let ready = 1; let initData = 2; @@ -136,6 +136,8 @@ let start = let onRequest = (_, _) => Ok(emptyJsonValue); + /* let send = */ + let rpc = Rpc.start( ~onNotification, diff --git a/test/editor/Core/Oni_Core_Test.re b/test/editor/Core/Oni_Core_Test.re new file mode 100644 index 0000000000..b2ec1574c9 --- /dev/null +++ b/test/editor/Core/Oni_Core_Test.re @@ -0,0 +1,2 @@ +module Helpers = Helpers; +module TestFramework = TestFramework; diff --git a/test/editor/Core/SetupTests.re b/test/editor/Core/SetupTests.re index daf0c28d7c..1faeb87921 100644 --- a/test/editor/Core/SetupTests.re +++ b/test/editor/Core/SetupTests.re @@ -3,7 +3,7 @@ open TestFramework; describe("Setup", ({test, _}) => test("ofString", ({expect}) => { - let setupInfo = "{neovim:\"/path/to/neovim\",node:\"/path/to/node\",textmateService:\"/path/to/textmate\",bundledExtensions:\"/path/to/extensions\",configuration:\"/path/to/config\",keybindings:\"/path/to/keybindings\"}"; + let setupInfo = "{neovim:\"/path/to/neovim\",node:\"/path/to/node\",textmateService:\"/path/to/textmate\",bundledExtensions:\"/path/to/extensions\",configuration:\"/path/to/config\",keybindings:\"/path/to/keybindings\", extensionHost: \"/path/to/exthost\"}"; let setup = Setup.ofString(setupInfo); expect.string(setup.neovimPath).toEqual("/path/to/neovim"); expect.string(setup.nodePath).toEqual("/path/to/node"); @@ -11,6 +11,9 @@ describe("Setup", ({test, _}) => expect.string(setup.bundledExtensionsPath).toEqual( "/path/to/extensions", ); + expect.string(setup.extensionHostPath).toEqual( + "/path/to/exthost", + ); expect.string(setup.configPath).toEqual("/path/to/config"); expect.string(setup.keybindingsPath).toEqual("/path/to/keybindings"); }) diff --git a/test/editor/Extensions/ExtensionClientTest.re b/test/editor/Extensions/ExtensionClientTest.re new file mode 100644 index 0000000000..497fd67259 --- /dev/null +++ b/test/editor/Extensions/ExtensionClientTest.re @@ -0,0 +1,33 @@ +open Oni_Core; +open Oni_Core_Test; +open Oni_Extensions; + +open TestFramework; + +describe("Extension Client", ({test, _}) => { + test("receive init message", ({expect}) => + Helpers.repeat(() => { + let setup = Setup.init(); + + let gotReadyMessage = ref(false); + + let onClosed = () => (); + let onMessage = (id, _) => { + if (id === ExtensionHostClient.Protocol.MessageType.ready) { + gotReadyMessage := true; + } + + Ok(None); + }; + + let extClient = + ExtensionHostClient.start(~onClosed, ~onMessage, setup); + + Oni_Core.Utility.waitForCondition(() => { + ExtensionHostClient.pump(extClient); + gotReadyMessage^; + }); + expect.bool(gotReadyMessage^).toBe(true); + + })); +}); diff --git a/test/editor/Extensions/TextmateTokenizerTests.re b/test/editor/Extensions/TextmateTokenizerTests.re index 4b3e0a7885..fa2ac62fc1 100644 --- a/test/editor/Extensions/TextmateTokenizerTests.re +++ b/test/editor/Extensions/TextmateTokenizerTests.re @@ -1,6 +1,10 @@ open Revery; open Oni_Core; +open Oni_Core_Test; +open Oni_Extensions; open TestFramework; +open Oni_Extensions.TextmateClient; +open Oni_Extensions.ExtensionContributions.Grammar; let reasonSyntaxPath = (setup: Setup.t) => setup.bundledExtensionsPath ++ "/vscode-reasonml/syntaxes/reason.json"; @@ -87,7 +91,7 @@ describe("Textmate Service", ({test, _}) => { ~onColorMap, ~onScopeLoaded, ~onTokens, - [{scopeName: "source.reason", path: reasonSyntaxPath(setup)}], + [{scopeName: "source.reason", path: reasonSyntaxPath(setup), language: None}], tmClient => { TextmateClient.preloadScope(tmClient, "source.reason"); @@ -137,7 +141,7 @@ describe("Textmate Service", ({test, _}) => { ~onColorMap, ~onScopeLoaded, ~onTokens, - [{scopeName: "source.reason", path: reasonSyntaxPath(setup)}], + [{scopeName: "source.reason", path: reasonSyntaxPath(setup), language: None}], tmClient => { TextmateClient.setTheme(tmClient, testThemePath(setup)); @@ -178,7 +182,7 @@ describe("Textmate Service", ({test, _}) => { ~onColorMap, ~onScopeLoaded, ~onTokens, - [{scopeName: "source.reason", path: reasonSyntaxPath(setup)}], + [{scopeName: "source.reason", path: reasonSyntaxPath(setup), language: None}], tmClient => { TextmateClient.setTheme(tmClient, testThemePath(setup)); diff --git a/test/editor/OniUnitTestRunner.re b/test/editor/OniUnitTestRunner.re index a39bdaff16..fe42d9e703 100644 --- a/test/editor/OniUnitTestRunner.re +++ b/test/editor/OniUnitTestRunner.re @@ -1,2 +1,4 @@ Oni_Core_Test.TestFramework.cli(); +Oni_Model_Test.TestFramework.cli(); Oni_Neovim_Test.TestFramework.cli(); +Oni_Extensions_Test.TestFramework.cli(); diff --git a/test/editor/dune b/test/editor/dune index 46a68a3e4a..b29892e1fb 100644 --- a/test/editor/dune +++ b/test/editor/dune @@ -5,6 +5,7 @@ (libraries yojson Oni_Core_Test + Oni_Extensions_Test Oni_Model_Test Oni_Neovim_Test )) From 359ab2a3fa0cd25118399214100a544bbbc1688c Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 08:56:39 -0700 Subject: [PATCH 08/20] Formatting --- src/editor/Extensions/ExtensionHostClient.re | 199 +++++++++--------- src/editor/Extensions/NodeProcess.re | 7 +- src/editor/bin/Oni2.re | 5 +- test/editor/Core/SetupTests.re | 4 +- test/editor/Extensions/ExtensionClientTest.re | 19 +- .../Extensions/TextmateTokenizerTests.re | 24 ++- 6 files changed, 138 insertions(+), 120 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index 9c4ce47c41..9128e8db14 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -2,7 +2,7 @@ * ExtensionHostClient.re * * This is a client-side API for integrating with our VSCode extension host API. - * + * */ open Oni_Core; @@ -10,89 +10,95 @@ open Reason_jsonrpc; /* open Revery; */ type t = { - process: NodeProcess.t, - rpc: Rpc.t, -} + process: NodeProcess.t, + rpc: Rpc.t, +}; let emptyJsonValue = `Assoc([]); type simpleCallback = unit => unit; let defaultCallback: simpleCallback = () => (); -module Protocol { +module Protocol = { + module MessageType = { + let initialized = 0; + let ready = 1; + let initData = 2; + let terminate = 3; + }; - module MessageType { - let initialized = 0; - let ready = 1; - let initData = 2; - let terminate = 3; + module LogLevel = { + let trace = 0; + let debug = 1; + let info = 2; + let warning = 3; + let error = 4; + let critical = 5; + let off = 6; + }; + + module Environment = { + type t = { + /* isExtensionDevelopmentDebug: bool, */ + appRootPath: string, + appSettingsHomePath: string, + /* extensionDevelopmentLocationPath: string, */ + /* extensionTestsLocationPath: string, */ + globalStorageHomePath: string, }; - module LogLevel { - let trace = 0; - let debug = 1; - let info = 2; - let warning = 3; - let error = 4; - let critical = 5; - let off = 6; + let create = + (~appRootPath, ~appSettingsHomePath, ~globalStorageHomePath, ()) => { + appRootPath, + appSettingsHomePath, + globalStorageHomePath, }; + }; - module Environment { - type t = { - /* isExtensionDevelopmentDebug: bool, */ - appRootPath: string, - appSettingsHomePath: string, - /* extensionDevelopmentLocationPath: string, */ - /* extensionTestsLocationPath: string, */ - globalStorageHomePath: string, - }; - - let create = (~appRootPath, ~appSettingsHomePath, ~globalStorageHomePath, ()) => { - appRootPath, - appSettingsHomePath, - globalStorageHomePath, - }; + /* module InitData { */ + /* [@deriving (show, yojson({strict: false, exn: true}))] */ + /* type t = { */ + /* parentPid: int, */ + /* environment: Environment.t, */ + /* logLevel: int, */ + /* logsLocationPath: string, */ + /* autoStart: bool, */ + /* }; */ + /* }; */ + + module Notification = { + exception NotificationParseException(string); + + type t = { + msgType: int, + reqId: int, + payload: Yojson.Safe.json, }; -/* module InitData { */ -/* [@deriving (show, yojson({strict: false, exn: true}))] */ -/* type t = { */ -/* parentPid: int, */ -/* environment: Environment.t, */ -/* logLevel: int, */ -/* logsLocationPath: string, */ -/* autoStart: bool, */ -/* }; */ -/* }; */ - - - module Notification { - - exception NotificationParseException(string); - - type t = { - msgType: int, - reqId: int, - payload: Yojson.Safe.json, - }; - - let of_yojson = (json: Yojson.Safe.json) => { - switch (json) { - | (`Assoc([ - ("type", `Int(t)), - ("reqId", `Int(reqId)), - ("payload", payload), - ])) => { - { msgType: t, reqId, payload} ; - } - | _ => raise(NotificationParseException("Unable to parse: " ++ Yojson.Safe.to_string(json))); - } - }; + let of_yojson = (json: Yojson.Safe.json) => { + switch (json) { + | `Assoc([ + ("type", `Int(t)), + ("reqId", `Int(reqId)), + ("payload", payload), + ]) => { + msgType: t, + reqId, + payload, + } + | _ => + raise( + NotificationParseException( + "Unable to parse: " ++ Yojson.Safe.to_string(json), + ), + ) + }; }; -} + }; +}; -type messageHandler = (int, Yojson.Safe.json) => result(option(Yojson.Safe.json), string); +type messageHandler = + (int, Yojson.Safe.json) => result(option(Yojson.Safe.json), string); let defaultMessageHandler = (_, _) => Ok(None); let start = @@ -101,42 +107,45 @@ let start = ~onClosed=defaultCallback, setup: Setup.t, ) => { - let args = ["--type=extensionHost"]; - let env = ["AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess"]; - let process = NodeProcess.start(~args, ~env, setup, setup.extensionHostPath); + let env = [ + "AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess", + ]; + let process = + NodeProcess.start(~args, ~env, setup, setup.extensionHostPath); let handleMessage = (id: int, _reqId: int, payload: Yojson.Safe.json) => { - - switch(onMessage(id, payload)) { - | Ok(None) => () - | Ok(Some(_)) => { - /* TODO: Send response */ - (); - } - | Error(_) => { - /* TODO: Send error */ - (); - } - }; - } + switch (onMessage(id, payload)) { + | Ok(None) => () + | Ok(Some(_)) => + /* TODO: Send response */ + () + | Error(_) => + /* TODO: Send error */ + () + }; + }; let onNotification = (n: Notification.t, _) => { switch (n.method, n.params) { - | ("host/msg", json) => { - open Protocol.Notification; - print_endline("[Extension Host Client] Unknown message: " ++ n.method); - print_endline ("JSON: " ++ Yojson.Safe.to_string(json)); - let parsedMessage = Protocol.Notification.of_yojson(json); - handleMessage(parsedMessage.msgType, parsedMessage.reqId, parsedMessage.payload); - } - | _ => print_endline("[Extension Host Client] Unknown message: " ++ n.method); + | ("host/msg", json) => + open Protocol.Notification; + print_endline("[Extension Host Client] Unknown message: " ++ n.method); + print_endline("JSON: " ++ Yojson.Safe.to_string(json)); + let parsedMessage = Protocol.Notification.of_yojson(json); + handleMessage( + parsedMessage.msgType, + parsedMessage.reqId, + parsedMessage.payload, + ); + | _ => + print_endline("[Extension Host Client] Unknown message: " ++ n.method) }; }; let onRequest = (_, _) => Ok(emptyJsonValue); - /* let send = */ + /* let send = */ let rpc = Rpc.start( @@ -147,7 +156,7 @@ let start = process.stdin, ); - {process, rpc} + {process, rpc}; }; let pump = (v: t) => Rpc.pump(v.rpc); diff --git a/src/editor/Extensions/NodeProcess.re b/src/editor/Extensions/NodeProcess.re index 51a836c0cb..d7753b2148 100644 --- a/src/editor/Extensions/NodeProcess.re +++ b/src/editor/Extensions/NodeProcess.re @@ -16,12 +16,9 @@ let start = (~args=[], ~env=[], setup: Setup.t, scriptPath: string) => { let (pstdin, stdin) = Unix.pipe(); let (stdout, pstdout) = Unix.pipe(); - let args = [setup.nodePath, scriptPath, ...args] - |> Array.of_list; + let args = [setup.nodePath, scriptPath, ...args] |> Array.of_list; - let env = env - |> Array.of_list - |> Array.append(Unix.environment()); + let env = env |> Array.of_list |> Array.append(Unix.environment()); let pid = Unix.create_process_env( diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index 345ab1be81..a3cd8d75ad 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -94,10 +94,7 @@ let init = app => { grammars, ); - let extHostClient = - Extensions.ExtensionHostClient.start( - setup - ); + let extHostClient = Extensions.ExtensionHostClient.start(setup); Extensions.TextmateClient.setTheme(tmClient, defaultThemePath); diff --git a/test/editor/Core/SetupTests.re b/test/editor/Core/SetupTests.re index 1faeb87921..81eaf6bf0e 100644 --- a/test/editor/Core/SetupTests.re +++ b/test/editor/Core/SetupTests.re @@ -11,9 +11,7 @@ describe("Setup", ({test, _}) => expect.string(setup.bundledExtensionsPath).toEqual( "/path/to/extensions", ); - expect.string(setup.extensionHostPath).toEqual( - "/path/to/exthost", - ); + expect.string(setup.extensionHostPath).toEqual("/path/to/exthost"); expect.string(setup.configPath).toEqual("/path/to/config"); expect.string(setup.keybindingsPath).toEqual("/path/to/keybindings"); }) diff --git a/test/editor/Extensions/ExtensionClientTest.re b/test/editor/Extensions/ExtensionClientTest.re index 497fd67259..dd450d05c3 100644 --- a/test/editor/Extensions/ExtensionClientTest.re +++ b/test/editor/Extensions/ExtensionClientTest.re @@ -4,7 +4,7 @@ open Oni_Extensions; open TestFramework; -describe("Extension Client", ({test, _}) => { +describe("Extension Client", ({test, _}) => test("receive init message", ({expect}) => Helpers.repeat(() => { let setup = Setup.init(); @@ -13,21 +13,20 @@ describe("Extension Client", ({test, _}) => { let onClosed = () => (); let onMessage = (id, _) => { - if (id === ExtensionHostClient.Protocol.MessageType.ready) { - gotReadyMessage := true; - } + if (id === ExtensionHostClient.Protocol.MessageType.ready) { + gotReadyMessage := true; + }; - Ok(None); + Ok(None); }; - let extClient = - ExtensionHostClient.start(~onClosed, ~onMessage, setup); + let extClient = ExtensionHostClient.start(~onClosed, ~onMessage, setup); Oni_Core.Utility.waitForCondition(() => { ExtensionHostClient.pump(extClient); gotReadyMessage^; }); expect.bool(gotReadyMessage^).toBe(true); - - })); -}); + }) + ) +); diff --git a/test/editor/Extensions/TextmateTokenizerTests.re b/test/editor/Extensions/TextmateTokenizerTests.re index fa2ac62fc1..7176be02db 100644 --- a/test/editor/Extensions/TextmateTokenizerTests.re +++ b/test/editor/Extensions/TextmateTokenizerTests.re @@ -91,7 +91,13 @@ describe("Textmate Service", ({test, _}) => { ~onColorMap, ~onScopeLoaded, ~onTokens, - [{scopeName: "source.reason", path: reasonSyntaxPath(setup), language: None}], + [ + { + scopeName: "source.reason", + path: reasonSyntaxPath(setup), + language: None, + }, + ], tmClient => { TextmateClient.preloadScope(tmClient, "source.reason"); @@ -141,7 +147,13 @@ describe("Textmate Service", ({test, _}) => { ~onColorMap, ~onScopeLoaded, ~onTokens, - [{scopeName: "source.reason", path: reasonSyntaxPath(setup), language: None}], + [ + { + scopeName: "source.reason", + path: reasonSyntaxPath(setup), + language: None, + }, + ], tmClient => { TextmateClient.setTheme(tmClient, testThemePath(setup)); @@ -182,7 +194,13 @@ describe("Textmate Service", ({test, _}) => { ~onColorMap, ~onScopeLoaded, ~onTokens, - [{scopeName: "source.reason", path: reasonSyntaxPath(setup), language: None}], + [ + { + scopeName: "source.reason", + path: reasonSyntaxPath(setup), + language: None, + }, + ], tmClient => { TextmateClient.setTheme(tmClient, testThemePath(setup)); From eaf0f58a208a0759a3b2f33258439ab1b688084d Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 09:09:08 -0700 Subject: [PATCH 09/20] Tweak runner --- test/editor/OniUnitTestRunner.re | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/editor/OniUnitTestRunner.re b/test/editor/OniUnitTestRunner.re index fe42d9e703..d4c5a2f942 100644 --- a/test/editor/OniUnitTestRunner.re +++ b/test/editor/OniUnitTestRunner.re @@ -1,4 +1,4 @@ Oni_Core_Test.TestFramework.cli(); Oni_Model_Test.TestFramework.cli(); -Oni_Neovim_Test.TestFramework.cli(); Oni_Extensions_Test.TestFramework.cli(); +Oni_Neovim_Test.TestFramework.cli(); From 77cd75e9b19cd731cfe60e49a706fa1fa8b8008e Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 09:25:21 -0700 Subject: [PATCH 10/20] Factor protocol out --- ExtensionHostProtocol.re | 69 +++++++++++++++++ src/editor/Extensions/ExtensionHostClient.re | 80 +------------------- 2 files changed, 71 insertions(+), 78 deletions(-) create mode 100644 ExtensionHostProtocol.re diff --git a/ExtensionHostProtocol.re b/ExtensionHostProtocol.re new file mode 100644 index 0000000000..59f6da7c61 --- /dev/null +++ b/ExtensionHostProtocol.re @@ -0,0 +1,69 @@ +/* + * ExtensionHostProtocol.re + * + * This module documents & types the protocol for communicating with the VSCode Extension Host. + * + */ + +module MessageType = { +let initialized = 0; +let ready = 1; +let initData = 2; +let terminate = 3; +}; + +module LogLevel = { +let trace = 0; +let debug = 1; +let info = 2; +let warning = 3; +let error = 4; +let critical = 5; +let off = 6; +}; + +module Environment = { +type t = { + /* isExtensionDevelopmentDebug: bool, */ + /* appRootPath: string, */ + /* appSettingsHomePath: string, */ + /* extensionDevelopmentLocationPath: string, */ + /* extensionTestsLocationPath: string, */ + globalStorageHomePath: string, +}; + +let create = + (~globalStorageHomePath, ()) => { + globalStorageHomePath, +}; +}; + + module Notification = { + exception NotificationParseException(string); + + type t = { + msgType: int, + reqId: int, + payload: Yojson.Safe.json, + }; + + let of_yojson = (json: Yojson.Safe.json) => { + switch (json) { + | `Assoc([ + ("type", `Int(t)), + ("reqId", `Int(reqId)), + ("payload", payload), + ]) => { + msgType: t, + reqId, + payload, + } + | _ => + raise( + NotificationParseException( + "Unable to parse: " ++ Yojson.Safe.to_string(json), + ), + ) + }; + }; + }; diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index 9128e8db14..fc0bdc0149 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -9,6 +9,8 @@ open Oni_Core; open Reason_jsonrpc; /* open Revery; */ +module Protocol = ExtensionHostProtocol; + type t = { process: NodeProcess.t, rpc: Rpc.t, @@ -19,84 +21,6 @@ let emptyJsonValue = `Assoc([]); type simpleCallback = unit => unit; let defaultCallback: simpleCallback = () => (); -module Protocol = { - module MessageType = { - let initialized = 0; - let ready = 1; - let initData = 2; - let terminate = 3; - }; - - module LogLevel = { - let trace = 0; - let debug = 1; - let info = 2; - let warning = 3; - let error = 4; - let critical = 5; - let off = 6; - }; - - module Environment = { - type t = { - /* isExtensionDevelopmentDebug: bool, */ - appRootPath: string, - appSettingsHomePath: string, - /* extensionDevelopmentLocationPath: string, */ - /* extensionTestsLocationPath: string, */ - globalStorageHomePath: string, - }; - - let create = - (~appRootPath, ~appSettingsHomePath, ~globalStorageHomePath, ()) => { - appRootPath, - appSettingsHomePath, - globalStorageHomePath, - }; - }; - - /* module InitData { */ - /* [@deriving (show, yojson({strict: false, exn: true}))] */ - /* type t = { */ - /* parentPid: int, */ - /* environment: Environment.t, */ - /* logLevel: int, */ - /* logsLocationPath: string, */ - /* autoStart: bool, */ - /* }; */ - /* }; */ - - module Notification = { - exception NotificationParseException(string); - - type t = { - msgType: int, - reqId: int, - payload: Yojson.Safe.json, - }; - - let of_yojson = (json: Yojson.Safe.json) => { - switch (json) { - | `Assoc([ - ("type", `Int(t)), - ("reqId", `Int(reqId)), - ("payload", payload), - ]) => { - msgType: t, - reqId, - payload, - } - | _ => - raise( - NotificationParseException( - "Unable to parse: " ++ Yojson.Safe.to_string(json), - ), - ) - }; - }; - }; -}; - type messageHandler = (int, Yojson.Safe.json) => result(option(Yojson.Safe.json), string); let defaultMessageHandler = (_, _) => Ok(None); From 78cace37152141f5beb2c012ebd0184d280a1b96 Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 09:26:05 -0700 Subject: [PATCH 11/20] Fix ExtHostProtocol path --- .../editor/Extensions/ExtensionHostProtocol.re | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ExtensionHostProtocol.re => src/editor/Extensions/ExtensionHostProtocol.re (100%) diff --git a/ExtensionHostProtocol.re b/src/editor/Extensions/ExtensionHostProtocol.re similarity index 100% rename from ExtensionHostProtocol.re rename to src/editor/Extensions/ExtensionHostProtocol.re From 038a7255400f935a76c1cdff852d7b2bc26c3204 Mon Sep 17 00:00:00 2001 From: bryphe Date: Tue, 26 Mar 2019 09:27:38 -0700 Subject: [PATCH 12/20] Formatting --- .../Extensions/ExtensionHostProtocol.re | 95 +++++++++---------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostProtocol.re b/src/editor/Extensions/ExtensionHostProtocol.re index 59f6da7c61..6ada9a152f 100644 --- a/src/editor/Extensions/ExtensionHostProtocol.re +++ b/src/editor/Extensions/ExtensionHostProtocol.re @@ -6,64 +6,63 @@ */ module MessageType = { -let initialized = 0; -let ready = 1; -let initData = 2; -let terminate = 3; + let initialized = 0; + let ready = 1; + let initData = 2; + let terminate = 3; }; module LogLevel = { -let trace = 0; -let debug = 1; -let info = 2; -let warning = 3; -let error = 4; -let critical = 5; -let off = 6; + let trace = 0; + let debug = 1; + let info = 2; + let warning = 3; + let error = 4; + let critical = 5; + let off = 6; }; module Environment = { -type t = { - /* isExtensionDevelopmentDebug: bool, */ - /* appRootPath: string, */ - /* appSettingsHomePath: string, */ - /* extensionDevelopmentLocationPath: string, */ - /* extensionTestsLocationPath: string, */ - globalStorageHomePath: string, -}; + type t = { + /* isExtensionDevelopmentDebug: bool, */ + /* appRootPath: string, */ + /* appSettingsHomePath: string, */ + /* extensionDevelopmentLocationPath: string, */ + /* extensionTestsLocationPath: string, */ + globalStorageHomePath: string, + }; -let create = - (~globalStorageHomePath, ()) => { - globalStorageHomePath, -}; + let create = (~globalStorageHomePath, ()) => { + globalStorageHomePath; + }; }; - module Notification = { - exception NotificationParseException(string); +module Notification = { + exception NotificationParseException(string); - type t = { - msgType: int, - reqId: int, - payload: Yojson.Safe.json, - }; + type t = { + msgType: int, + reqId: int, + payload: Yojson.Safe.json, + }; - let of_yojson = (json: Yojson.Safe.json) => { - switch (json) { - | `Assoc([ - ("type", `Int(t)), - ("reqId", `Int(reqId)), - ("payload", payload), - ]) => { - msgType: t, - reqId, - payload, - } - | _ => - raise( - NotificationParseException( - "Unable to parse: " ++ Yojson.Safe.to_string(json), - ), - ) - }; + let of_yojson = (json: Yojson.Safe.json) => { + switch (json) { + | `Assoc([ + ("type", `Int(t)), + ("reqId", `Int(reqId)), + ("payload", payload), + ]) => { + msgType: t, + reqId, + payload, + } + | _ => + raise( + NotificationParseException( + "Unable to parse: " ++ Yojson.Safe.to_string(json), + ), + ) }; }; +}; From 7b96e01767b8c86c3c22979680b6045655b43baf Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 07:53:25 -0700 Subject: [PATCH 13/20] Fix merge conflict --- test/editor/dune | 1 - 1 file changed, 1 deletion(-) diff --git a/test/editor/dune b/test/editor/dune index 8811253219..70dc1087d6 100644 --- a/test/editor/dune +++ b/test/editor/dune @@ -8,7 +8,6 @@ Oni_Core_Test Oni_Extensions_Test Oni_Model_Test - Oni_Extensions_Test Oni_Neovim_Test )) From 5370223fd49ffc063f99b611904509238c97f786 Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 07:53:32 -0700 Subject: [PATCH 14/20] Start stubbing out InitDat --- .../Extensions/ExtensionHostInitData.re | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/editor/Extensions/ExtensionHostInitData.re diff --git a/src/editor/Extensions/ExtensionHostInitData.re b/src/editor/Extensions/ExtensionHostInitData.re new file mode 100644 index 0000000000..776b3daa36 --- /dev/null +++ b/src/editor/Extensions/ExtensionHostInitData.re @@ -0,0 +1,28 @@ +/* + * ExtensionHostInitData.re + * + * Module documenting the initialization data required for spinning up + * and activating the extension host + */ + +module ExtensionInfo { + type t; +}; + +module Workspace { + type t; +}; + +module Environment { + type t = { + globalStorageHomePath: string, + }; +}; + +type t = { + extensions: list(ExtensionInfo.t), + parentPid: int, + environment: Environment.t, + logsLocationPath: string, + autoStart: bool, +}; From 613eccf4e6ad1c49e0d18473a736793442b1f6e9 Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 08:03:15 -0700 Subject: [PATCH 15/20] Get ExtensionHostInitData compiling --- src/editor/Core/Filesystem.rei | 2 ++ .../Extensions/ExtensionHostInitData.re | 35 +++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/editor/Core/Filesystem.rei b/src/editor/Core/Filesystem.rei index 349447292a..6baae75039 100644 --- a/src/editor/Core/Filesystem.rei +++ b/src/editor/Core/Filesystem.rei @@ -28,6 +28,8 @@ let mkdir: (string, ~perm: int=?, unit) => t(unit); let rmdir: string => t(unit); +let unsafeFindHome: unit => string; + let getOniDirectory: string => t(string); let createOniConfigFile: string => t(string); diff --git a/src/editor/Extensions/ExtensionHostInitData.re b/src/editor/Extensions/ExtensionHostInitData.re index 776b3daa36..7a39117757 100644 --- a/src/editor/Extensions/ExtensionHostInitData.re +++ b/src/editor/Extensions/ExtensionHostInitData.re @@ -5,20 +5,37 @@ * and activating the extension host */ +open Oni_Core; + module ExtensionInfo { - type t; + [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] + type t = { + identifier: string, + }; }; module Workspace { - type t; + [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] + type t = { + __test: string, + }; }; module Environment { + [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] type t = { globalStorageHomePath: string, }; + + let create = (~globalStorageHomePath=Filesystem.unsafeFindHome(), ()) => { + let ret: t = { + globalStorageHomePath: globalStorageHomePath, + }; + ret; + }; }; +[@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] type t = { extensions: list(ExtensionInfo.t), parentPid: int, @@ -26,3 +43,17 @@ type t = { logsLocationPath: string, autoStart: bool, }; + +let create = ( + ~parentPid= Unix.getpid(), + ~extensions= [], + ~environment= Environment.create(), + ~logsLocationPath=Filesystem.unsafeFindHome(), + ~autoStart=true, + ()) => { + parentPid, + extensions, + environment, + logsLocationPath, + autoStart, + }; From da0640431a8309082f9b52d62caf5814b9f4c441 Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 08:03:45 -0700 Subject: [PATCH 16/20] Formatting --- .../Extensions/ExtensionHostInitData.re | 70 +++++++++---------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostInitData.re b/src/editor/Extensions/ExtensionHostInitData.re index 7a39117757..2adfaf35ad 100644 --- a/src/editor/Extensions/ExtensionHostInitData.re +++ b/src/editor/Extensions/ExtensionHostInitData.re @@ -7,53 +7,47 @@ open Oni_Core; -module ExtensionInfo { - [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] - type t = { - identifier: string, - }; +module ExtensionInfo = { + [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] + type t = {identifier: string}; }; -module Workspace { +module Workspace = { [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] - type t = { - __test: string, - }; + type t = {__test: string}; }; -module Environment { - [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] - type t = { - globalStorageHomePath: string, - }; +module Environment = { + [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] + type t = {globalStorageHomePath: string}; - let create = (~globalStorageHomePath=Filesystem.unsafeFindHome(), ()) => { - let ret: t = { - globalStorageHomePath: globalStorageHomePath, - }; - ret; - }; + let create = (~globalStorageHomePath=Filesystem.unsafeFindHome(), ()) => { + let ret: t = {globalStorageHomePath: globalStorageHomePath}; + ret; + }; }; [@deriving (show({with_path: false}), yojson({strict: false, exn: true}))] type t = { - extensions: list(ExtensionInfo.t), - parentPid: int, - environment: Environment.t, - logsLocationPath: string, - autoStart: bool, + extensions: list(ExtensionInfo.t), + parentPid: int, + environment: Environment.t, + logsLocationPath: string, + autoStart: bool, }; -let create = ( - ~parentPid= Unix.getpid(), - ~extensions= [], - ~environment= Environment.create(), - ~logsLocationPath=Filesystem.unsafeFindHome(), - ~autoStart=true, - ()) => { - parentPid, - extensions, - environment, - logsLocationPath, - autoStart, - }; +let create = + ( + ~parentPid=Unix.getpid(), + ~extensions=[], + ~environment=Environment.create(), + ~logsLocationPath=Filesystem.unsafeFindHome(), + ~autoStart=true, + (), + ) => { + parentPid, + extensions, + environment, + logsLocationPath, + autoStart, +}; From 9d3cd937dafc97d5d4f77dd9f5af687278ce083a Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 08:26:05 -0700 Subject: [PATCH 17/20] Debugging exception on startup --- src/editor/Extensions/ExtensionHostClient.re | 53 ++++++++++++++----- .../Extensions/ExtensionHostProtocol.re | 2 + src/editor/bin/Oni2.re | 5 +- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index fc0bdc0149..c5e03b1ec9 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -27,10 +27,12 @@ let defaultMessageHandler = (_, _) => Ok(None); let start = ( + ~initData=ExtensionHostInitData.create(), ~onMessage=defaultMessageHandler, ~onClosed=defaultCallback, setup: Setup.t, ) => { + print_endline ("got here"); let args = ["--type=extensionHost"]; let env = [ "AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess", @@ -38,16 +40,43 @@ let start = let process = NodeProcess.start(~args, ~env, setup, setup.extensionHostPath); + let lastReqId = ref(0); + let rpcRef = ref(None); + + let send = (msgType: int, msg: Yojson.Safe.json) => { + switch (rpcRef^) { + | None => prerr_endline ("RPC not initialized."); + | Some(v) => { + incr(lastReqId); + let reqId = lastReqId^; + + let request = `Assoc([ + ("type", `Int(msgType)), + ("reqId", `Int(reqId)), + ("payload", msg), + ]); + + print_endline ("Sending request"); + Rpc.sendNotification(v, "ext/msg", request); + } + }; + }; + let handleMessage = (id: int, _reqId: int, payload: Yojson.Safe.json) => { - switch (onMessage(id, payload)) { - | Ok(None) => () - | Ok(Some(_)) => - /* TODO: Send response */ - () - | Error(_) => - /* TODO: Send error */ - () - }; + if (id == Protocol.MessageType.initialized) { + print_endline ("HANDLE MESSAGE"); + send(Protocol.MessageType.initData, ExtensionHostInitData.to_yojson(initData)); + } else { + switch (onMessage(id, payload)) { + | Ok(None) => () + | Ok(Some(_)) => + /* TODO: Send response */ + () + | Error(_) => + /* TODO: Send error */ + () + }; + } }; let onNotification = (n: Notification.t, _) => { @@ -69,8 +98,6 @@ let start = let onRequest = (_, _) => Ok(emptyJsonValue); - /* let send = */ - let rpc = Rpc.start( ~onNotification, @@ -80,7 +107,9 @@ let start = process.stdin, ); - {process, rpc}; + rpcRef := Some(rpc); + + {process, rpc }; }; let pump = (v: t) => Rpc.pump(v.rpc); diff --git a/src/editor/Extensions/ExtensionHostProtocol.re b/src/editor/Extensions/ExtensionHostProtocol.re index 6ada9a152f..1aba9c5566 100644 --- a/src/editor/Extensions/ExtensionHostProtocol.re +++ b/src/editor/Extensions/ExtensionHostProtocol.re @@ -10,6 +10,7 @@ module MessageType = { let ready = 1; let initData = 2; let terminate = 3; + let requestJsonArgs = 4; }; module LogLevel = { @@ -22,6 +23,7 @@ module LogLevel = { let off = 6; }; + module Environment = { type t = { /* isExtensionDevelopmentDebug: bool, */ diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index 439430c946..9a9cf6f79a 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -104,7 +104,8 @@ let init = app => { grammars, ); - let extHostClient = Extensions.ExtensionHostClient.start(setup); + /* print_endline ("starting exthost client"); */ + /* let extHostClient = Extensions.ExtensionHostClient.start(setup); */ Extensions.TextmateClient.setTheme(tmClient, defaultThemePath); @@ -224,7 +225,7 @@ let init = app => { _ => { nvimApi.pump(); Extensions.TextmateClient.pump(tmClient); - Extensions.ExtensionHostClient.pump(extHostClient); + /* Extensions.ExtensionHostClient.pump(extHostClient); */ }, Seconds(0.), ); From 99a78bdb29d6ac42c8c71e7a3769c633af55cb07 Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 09:06:25 -0700 Subject: [PATCH 18/20] Refactor interface, test for 'initialized' event --- src/editor/Extensions/ExtensionHostClient.re | 7 ++++-- src/editor/Extensions/Oni_Extensions.re | 1 + src/editor/bin/Oni2.re | 10 +++++--- test/editor/Extensions/ExtensionClientTest.re | 24 +++++++------------ 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index c5e03b1ec9..a3c0679d78 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -28,6 +28,7 @@ let defaultMessageHandler = (_, _) => Ok(None); let start = ( ~initData=ExtensionHostInitData.create(), + ~onInitialized=defaultCallback, ~onMessage=defaultMessageHandler, ~onClosed=defaultCallback, setup: Setup.t, @@ -36,6 +37,7 @@ let start = let args = ["--type=extensionHost"]; let env = [ "AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess", + "VSCODE_PARENT_PID=" ++ string_of_int(Unix.getpid()), ]; let process = NodeProcess.start(~args, ~env, setup, setup.extensionHostPath); @@ -63,9 +65,11 @@ let start = }; let handleMessage = (id: int, _reqId: int, payload: Yojson.Safe.json) => { - if (id == Protocol.MessageType.initialized) { + if (id == Protocol.MessageType.ready) { print_endline ("HANDLE MESSAGE"); send(Protocol.MessageType.initData, ExtensionHostInitData.to_yojson(initData)); + } else if(id == Protocol.MessageType.initialized) { + onInitialized(); } else { switch (onMessage(id, payload)) { | Ok(None) => () @@ -83,7 +87,6 @@ let start = switch (n.method, n.params) { | ("host/msg", json) => open Protocol.Notification; - print_endline("[Extension Host Client] Unknown message: " ++ n.method); print_endline("JSON: " ++ Yojson.Safe.to_string(json)); let parsedMessage = Protocol.Notification.of_yojson(json); handleMessage( diff --git a/src/editor/Extensions/Oni_Extensions.re b/src/editor/Extensions/Oni_Extensions.re index 3fff74ecf7..9abd14ddb1 100644 --- a/src/editor/Extensions/Oni_Extensions.re +++ b/src/editor/Extensions/Oni_Extensions.re @@ -8,6 +8,7 @@ module ColorMap = ColorMap; module ColorizedToken = ColorizedToken; module ExtensionContributions = ExtensionContributions; module ExtensionHostClient = ExtensionHostClient; +module ExtensionHostInitData = ExtensionHostInitData; module ExtensionManifest = ExtensionManifest; module ExtensionScanner = ExtensionScanner; module TextmateClient = TextmateClient; diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index 9a9cf6f79a..e191447981 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -104,8 +104,12 @@ let init = app => { grammars, ); - /* print_endline ("starting exthost client"); */ - /* let extHostClient = Extensions.ExtensionHostClient.start(setup); */ + let onExtHostClosed = () => print_endline ("ext host closed"); + + let extHostClient = Extensions.ExtensionHostClient.start( + ~onClosed=onExtHostClosed, + setup + ); Extensions.TextmateClient.setTheme(tmClient, defaultThemePath); @@ -225,7 +229,7 @@ let init = app => { _ => { nvimApi.pump(); Extensions.TextmateClient.pump(tmClient); - /* Extensions.ExtensionHostClient.pump(extHostClient); */ + Extensions.ExtensionHostClient.pump(extHostClient); }, Seconds(0.), ); diff --git a/test/editor/Extensions/ExtensionClientTest.re b/test/editor/Extensions/ExtensionClientTest.re index dd450d05c3..079dee88df 100644 --- a/test/editor/Extensions/ExtensionClientTest.re +++ b/test/editor/Extensions/ExtensionClientTest.re @@ -4,29 +4,21 @@ open Oni_Extensions; open TestFramework; -describe("Extension Client", ({test, _}) => - test("receive init message", ({expect}) => +describe("Extension Client", ({test, _}) => { + test("gets initialized message", ({expect}) => Helpers.repeat(() => { let setup = Setup.init(); - let gotReadyMessage = ref(false); + let initialized = ref(false); - let onClosed = () => (); - let onMessage = (id, _) => { - if (id === ExtensionHostClient.Protocol.MessageType.ready) { - gotReadyMessage := true; - }; - - Ok(None); - }; - - let extClient = ExtensionHostClient.start(~onClosed, ~onMessage, setup); + let onInitialized = () => initialized := true; + let extClient = ExtensionHostClient.start(~onInitialized, setup); Oni_Core.Utility.waitForCondition(() => { ExtensionHostClient.pump(extClient); - gotReadyMessage^; + initialized^; }); - expect.bool(gotReadyMessage^).toBe(true); + expect.bool(initialized^).toBe(true); }) ) -); +}); From f7f58ad9233bdf82d2fde262e6290b49f2f939c0 Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 09:06:50 -0700 Subject: [PATCH 19/20] Formatting --- src/editor/Extensions/ExtensionHostClient.re | 70 ++++++++++--------- .../Extensions/ExtensionHostProtocol.re | 1 - src/editor/bin/Oni2.re | 8 +-- test/editor/Extensions/ExtensionClientTest.re | 4 +- 4 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index a3c0679d78..ab435a0314 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -33,7 +33,7 @@ let start = ~onClosed=defaultCallback, setup: Setup.t, ) => { - print_endline ("got here"); + print_endline("got here"); let args = ["--type=extensionHost"]; let env = [ "AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess", @@ -46,42 +46,44 @@ let start = let rpcRef = ref(None); let send = (msgType: int, msg: Yojson.Safe.json) => { - switch (rpcRef^) { - | None => prerr_endline ("RPC not initialized."); - | Some(v) => { - incr(lastReqId); - let reqId = lastReqId^; - - let request = `Assoc([ - ("type", `Int(msgType)), - ("reqId", `Int(reqId)), - ("payload", msg), - ]); - - print_endline ("Sending request"); - Rpc.sendNotification(v, "ext/msg", request); - } - }; + switch (rpcRef^) { + | None => prerr_endline("RPC not initialized.") + | Some(v) => + incr(lastReqId); + let reqId = lastReqId^; + + let request = + `Assoc([ + ("type", `Int(msgType)), + ("reqId", `Int(reqId)), + ("payload", msg), + ]); + + print_endline("Sending request"); + Rpc.sendNotification(v, "ext/msg", request); + }; }; - let handleMessage = (id: int, _reqId: int, payload: Yojson.Safe.json) => { + let handleMessage = (id: int, _reqId: int, payload: Yojson.Safe.json) => if (id == Protocol.MessageType.ready) { - print_endline ("HANDLE MESSAGE"); - send(Protocol.MessageType.initData, ExtensionHostInitData.to_yojson(initData)); - } else if(id == Protocol.MessageType.initialized) { - onInitialized(); + print_endline("HANDLE MESSAGE"); + send( + Protocol.MessageType.initData, + ExtensionHostInitData.to_yojson(initData), + ); + } else if (id == Protocol.MessageType.initialized) { + onInitialized(); } else { - switch (onMessage(id, payload)) { - | Ok(None) => () - | Ok(Some(_)) => - /* TODO: Send response */ - () - | Error(_) => - /* TODO: Send error */ - () - }; - } - }; + switch (onMessage(id, payload)) { + | Ok(None) => () + | Ok(Some(_)) => + /* TODO: Send response */ + () + | Error(_) => + /* TODO: Send error */ + () + }; + }; let onNotification = (n: Notification.t, _) => { switch (n.method, n.params) { @@ -112,7 +114,7 @@ let start = rpcRef := Some(rpc); - {process, rpc }; + {process, rpc}; }; let pump = (v: t) => Rpc.pump(v.rpc); diff --git a/src/editor/Extensions/ExtensionHostProtocol.re b/src/editor/Extensions/ExtensionHostProtocol.re index 1aba9c5566..dc201ffba5 100644 --- a/src/editor/Extensions/ExtensionHostProtocol.re +++ b/src/editor/Extensions/ExtensionHostProtocol.re @@ -23,7 +23,6 @@ module LogLevel = { let off = 6; }; - module Environment = { type t = { /* isExtensionDevelopmentDebug: bool, */ diff --git a/src/editor/bin/Oni2.re b/src/editor/bin/Oni2.re index e191447981..d881b09c82 100644 --- a/src/editor/bin/Oni2.re +++ b/src/editor/bin/Oni2.re @@ -104,12 +104,10 @@ let init = app => { grammars, ); - let onExtHostClosed = () => print_endline ("ext host closed"); + let onExtHostClosed = () => print_endline("ext host closed"); - let extHostClient = Extensions.ExtensionHostClient.start( - ~onClosed=onExtHostClosed, - setup - ); + let extHostClient = + Extensions.ExtensionHostClient.start(~onClosed=onExtHostClosed, setup); Extensions.TextmateClient.setTheme(tmClient, defaultThemePath); diff --git a/test/editor/Extensions/ExtensionClientTest.re b/test/editor/Extensions/ExtensionClientTest.re index 079dee88df..d950567b2c 100644 --- a/test/editor/Extensions/ExtensionClientTest.re +++ b/test/editor/Extensions/ExtensionClientTest.re @@ -4,7 +4,7 @@ open Oni_Extensions; open TestFramework; -describe("Extension Client", ({test, _}) => { +describe("Extension Client", ({test, _}) => test("gets initialized message", ({expect}) => Helpers.repeat(() => { let setup = Setup.init(); @@ -21,4 +21,4 @@ describe("Extension Client", ({test, _}) => { expect.bool(initialized^).toBe(true); }) ) -}); +); From 9ea3880261919ba275b32be10ddd830fecf30085 Mon Sep 17 00:00:00 2001 From: bryphe Date: Wed, 27 Mar 2019 09:08:10 -0700 Subject: [PATCH 20/20] Remove logging --- src/editor/Extensions/ExtensionHostClient.re | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/editor/Extensions/ExtensionHostClient.re b/src/editor/Extensions/ExtensionHostClient.re index ab435a0314..a7519921be 100644 --- a/src/editor/Extensions/ExtensionHostClient.re +++ b/src/editor/Extensions/ExtensionHostClient.re @@ -33,7 +33,6 @@ let start = ~onClosed=defaultCallback, setup: Setup.t, ) => { - print_endline("got here"); let args = ["--type=extensionHost"]; let env = [ "AMD_ENTRYPOINT=vs/workbench/services/extensions/node/extensionHostProcess", @@ -59,14 +58,12 @@ let start = ("payload", msg), ]); - print_endline("Sending request"); Rpc.sendNotification(v, "ext/msg", request); }; }; let handleMessage = (id: int, _reqId: int, payload: Yojson.Safe.json) => if (id == Protocol.MessageType.ready) { - print_endline("HANDLE MESSAGE"); send( Protocol.MessageType.initData, ExtensionHostInitData.to_yojson(initData),