Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Merge pull request #4 from vim-denops/singleton
Browse files Browse the repository at this point in the history
Make denops singleton and optimize APIs
  • Loading branch information
lambdalisue authored Feb 20, 2021
2 parents a2abc43 + c4ecdbf commit 4658e75
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 42 deletions.
34 changes: 34 additions & 0 deletions api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Context object which is exposed in l: namespace
*/
export interface Context {
[key: string]: unknown;
}

/**
* API of denops core
*/
export interface Api {
/**
* Call {func} with given {args} and return the result
*/
call(func: string, ...args: unknown[]): Promise<unknown>;

/**
* Execute {cmd} under the {context}
*/
cmd(cmd: string, context: Context): Promise<void>;

/**
* Evaluate {expr} under the {context} and return result
*/
eval(expr: string, context: Context): Promise<unknown>;
}

/**
* Return if a given value is Context object or not
*/
export function isContext(value: unknown): value is Context {
const t = typeof value;
return t === "function" || (t === "object" && value !== null);
}
29 changes: 29 additions & 0 deletions cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// deno-lint-ignore no-explicit-any
const that = globalThis as any;

// Thread-local cache
that.denopsCache = {};

/**
* Get a value from the thread-local context
*/
export function getCache<T = unknown>(name: string): T | undefined {
return that.denopsCache[name];
}

/**
* Set a value to the thread-local cache
*/
export function setCache<T>(name: string, value: T): void {
that.denopsCache[name] = value;
}

/**
* Get a value from the thread-local cache or set if no value exist
*/
export function getCacheOrElse<T>(name: string, factory: () => T): T {
if (!that.denopsCache[name]) {
that.denopsCache[name] = factory();
}
return that.denopsCache[name];
}
72 changes: 32 additions & 40 deletions denops.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Dispatcher, Session } from "./deps.ts";
import { Api, Context } from "./api.ts";
import { getCacheOrElse } from "./cache.ts";
import { WorkerReader, WorkerWriter } from "./worker.ts";

/**
* A denops host (Vim/Neovim) interface.
* Denops provides API to access plugin host (Vim/Neovim)
*/
export class Denops {
export class Denops implements Api {
#name: string;
#session: Session;

constructor(
private constructor(
name: string,
reader: Deno.Reader & Deno.Closer,
writer: Deno.Writer,
Expand All @@ -18,20 +20,33 @@ export class Denops {
this.#session = new Session(reader, writer, dispatcher);
}

/**
* Get thread-local denops instance
*/
static get(): Denops {
return getCacheOrElse("denops", () => {
// deno-lint-ignore no-explicit-any
const worker = self as any;
const reader = getCacheOrElse(
"workerReader",
() => new WorkerReader(worker),
);
const writer = getCacheOrElse(
"workerWriter",
() => new WorkerWriter(worker),
);
return new Denops(worker.name, reader, writer);
});
}

/**
* Start main event-loop of the plugin
*/
static start(main: (denops: Denops) => Promise<void>): void {
// deno-lint-ignore no-explicit-any
const name = (self as any).name ?? "unknown";
// deno-lint-ignore no-explicit-any
const worker = (self as any) as Worker;
const reader = new WorkerReader(worker);
const writer = new WorkerWriter(worker);
const denops = new Denops(name, reader, writer);
const denops = Denops.get();
const waiter = Promise.all([denops.#session.listen(), main(denops)]);
waiter.catch((e) => {
console.error("Unexpected error on denops server", e);
console.error(`Unexpected error occured in '${denops.name}'`, e);
});
}

Expand All @@ -42,39 +57,16 @@ export class Denops {
return this.#name;
}

/**
* Execute a command (expr) on the host.
*/
async command(expr: string): Promise<void> {
await this.#session.notify("command", expr);
async cmd(cmd: string, context: Context = {}): Promise<void> {
await this.#session.call("cmd", cmd, context);
}

/**
* Evaluate an expression (expr) on the host and return the result.
*/
async eval(expr: string): Promise<unknown> {
return await this.#session.call("eval", expr);
async eval(expr: string, context: Context = {}): Promise<unknown> {
return await this.#session.call("eval", expr, context);
}

/**
* Call a function on the host and return the result.
*/
async call(method: string, params: unknown[]): Promise<unknown> {
return await this.#session.call("call", method, params);
}

/**
* Echo text on the host.
*/
async echo(text: string): Promise<void> {
await this.#session.notify("echo", [text]);
}

/**
* Echo text on the host.
*/
async echomsg(text: string): Promise<void> {
await this.#session.notify("echomsg", [text]);
async call(func: string, ...args: unknown[]): Promise<unknown> {
return await this.#session.call("call", func, ...args);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions deps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { Queue } from "https://deno.land/x/[email protected]/mod.ts";
export { Session } from "https://deno.land/x/msgpack_rpc@v2.4/mod.ts";
export type { Dispatcher } from "https://deno.land/x/msgpack_rpc@v2.4/mod.ts";
export { Session } from "https://deno.land/x/msgpack_rpc@v2.6/mod.ts";
export type { Dispatcher } from "https://deno.land/x/msgpack_rpc@v2.6/mod.ts";
export { copy as copyBytes } from "https://deno.land/[email protected]/bytes/mod.ts";
2 changes: 2 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from "./api.ts";
export * from "./cache.ts";
export * from "./denops.ts";
export * from "./worker.ts";

0 comments on commit 4658e75

Please sign in to comment.