diff --git a/denops/ddc/app.ts b/denops/ddc/app.ts index eb7e1ba..0c22fc4 100644 --- a/denops/ddc/app.ts +++ b/denops/ddc/app.ts @@ -1,6 +1,7 @@ import { Ddc } from "./ddc.ts"; -import { ContextBuilder, type ContextCallbacks } from "./context.ts"; +import { ContextBuilderImpl } from "./context.ts"; import type { + ContextCallbacks, DdcEvent, DdcExtType, DdcItem, @@ -26,7 +27,7 @@ import { toFileUrl } from "jsr:@std/path@~1.0.2/to-file-url"; export const main: Entrypoint = (denops: Denops) => { const loader = new Loader(); const ddc = new Ddc(loader); - const contextBuilder = new ContextBuilder(); + const contextBuilder = new ContextBuilderImpl(); const cbContext = createCallbackContext(); const lock = new Lock(0); let queuedEvent: DdcEvent | null = null; diff --git a/denops/ddc/base/config.ts b/denops/ddc/base/config.ts index 455b8e0..ba1201d 100644 --- a/denops/ddc/base/config.ts +++ b/denops/ddc/base/config.ts @@ -1,5 +1,4 @@ -import type { ContextBuilder } from "../context.ts"; -import type { DdcExtType } from "../types.ts"; +import type { ContextBuilder, DdcExtType } from "../types.ts"; import type { Denops } from "jsr:@denops/std@~7.1.0"; diff --git a/denops/ddc/base/filter.ts b/denops/ddc/base/filter.ts index 4c07aba..e1c998d 100644 --- a/denops/ddc/base/filter.ts +++ b/denops/ddc/base/filter.ts @@ -1,4 +1,5 @@ import type { + BaseParams, Context, DdcEvent, DdcOptions, @@ -10,15 +11,13 @@ import type { import type { Denops } from "jsr:@denops/std@~7.1.0"; -export type BaseFilterParams = Record; - -export type OnInitArguments = { +export type OnInitArguments = { denops: Denops; filterOptions: FilterOptions; filterParams: Params; }; -export type OnEventArguments = { +export type OnEventArguments = { denops: Denops; context: Context; onCallback: OnCallback; @@ -27,7 +26,7 @@ export type OnEventArguments = { filterParams: Params; }; -export type FilterArguments = { +export type FilterArguments = { denops: Denops; context: Context; onCallback: OnCallback; @@ -39,7 +38,7 @@ export type FilterArguments = { items: Item[]; }; -export abstract class BaseFilter { +export abstract class BaseFilter { name = ""; isInitialized = false; apiVersion = 4; diff --git a/denops/ddc/base/source.ts b/denops/ddc/base/source.ts index aa19f2f..0757c75 100644 --- a/denops/ddc/base/source.ts +++ b/denops/ddc/base/source.ts @@ -1,4 +1,5 @@ import type { + BaseParams, Context, DdcEvent, DdcGatherItems, @@ -10,31 +11,26 @@ import type { SourceOptions, } from "../types.ts"; import { convertKeywordPattern } from "../utils.ts"; -import type { Loader } from "../loader.ts"; import type { Denops } from "jsr:@denops/std@~7.1.0"; -export type BaseSourceParams = Record; - -export type OnInitArguments = { +export type OnInitArguments = { denops: Denops; sourceOptions: SourceOptions; sourceParams: Params; - loader: Loader; }; -export type OnEventArguments = { +export type OnEventArguments = { denops: Denops; context: Context; onCallback: OnCallback; options: DdcOptions; sourceOptions: SourceOptions; sourceParams: Params; - loader: Loader; }; export type OnCompleteDoneArguments< - Params extends BaseSourceParams, + Params extends BaseParams, UserData extends unknown = unknown, > = { denops: Denops; @@ -43,13 +39,12 @@ export type OnCompleteDoneArguments< options: DdcOptions; sourceOptions: SourceOptions; sourceParams: Params; - loader: Loader; // To prevent users from accessing internal variables. userData: UserData; }; export type GetPreviewerArguments< - Params extends BaseSourceParams, + Params extends BaseParams, UserData extends unknown = unknown, > = { denops: Denops; @@ -59,34 +54,31 @@ export type GetPreviewerArguments< sourceParams: Params; item: Item; previewContext: PreviewContext; - loader: Loader; }; -export type GetCompletePositionArguments = { +export type GetCompletePositionArguments = { denops: Denops; context: Context; onCallback: OnCallback; options: DdcOptions; sourceOptions: SourceOptions; sourceParams: Params; - loader: Loader; }; -export type GatherArguments = { +export type GatherArguments = { denops: Denops; context: Context; onCallback: OnCallback; options: DdcOptions; sourceOptions: SourceOptions; sourceParams: Params; - loader: Loader; completePos: number; completeStr: string; isIncomplete?: boolean; }; export abstract class BaseSource< - Params extends BaseSourceParams, + Params extends BaseParams, UserData extends unknown = unknown, > { name = ""; diff --git a/denops/ddc/base/ui.ts b/denops/ddc/base/ui.ts index eb88aa3..148a8f4 100644 --- a/denops/ddc/base/ui.ts +++ b/denops/ddc/base/ui.ts @@ -1,16 +1,20 @@ -import type { Context, DdcItem, DdcOptions, UiOptions } from "../types.ts"; +import type { + BaseParams, + Context, + DdcItem, + DdcOptions, + UiOptions, +} from "../types.ts"; import type { Denops } from "jsr:@denops/std@~7.1.0"; -export type BaseUiParams = Record; - -export type OnInitArguments = { +export type OnInitArguments = { denops: Denops; uiOptions: UiOptions; uiParams: Params; }; -export type SkipCompletionArguments = { +export type SkipCompletionArguments = { denops: Denops; context: Context; options: DdcOptions; @@ -18,7 +22,7 @@ export type SkipCompletionArguments = { uiParams: Params; }; -export type ShowArguments = { +export type ShowArguments = { denops: Denops; context: Context; options: DdcOptions; @@ -28,7 +32,7 @@ export type ShowArguments = { uiParams: Params; }; -export type HideArguments = { +export type HideArguments = { denops: Denops; context: Context; options: DdcOptions; @@ -36,7 +40,7 @@ export type HideArguments = { uiParams: Params; }; -export type VisibleArguments = { +export type VisibleArguments = { denops: Denops; context: Context; options: DdcOptions; @@ -44,7 +48,7 @@ export type VisibleArguments = { uiParams: Params; }; -export abstract class BaseUi { +export abstract class BaseUi { name = ""; isInitialized = false; apiVersion = 2; diff --git a/denops/ddc/context.ts b/denops/ddc/context.ts index 31a76b2..46be59e 100644 --- a/denops/ddc/context.ts +++ b/denops/ddc/context.ts @@ -1,8 +1,9 @@ import type { - BaseFilterParams, - BaseSourceParams, - BaseUiParams, + BaseParams, Context, + ContextBuilder, + ContextCallback, + ContextCallbacks, DdcEvent, DdcOptions, FilterOptions, @@ -42,19 +43,9 @@ function overwrite(a: T, b: Partial): T { export const mergeUiOptions: Merge = overwrite; export const mergeSourceOptions: Merge = overwrite; export const mergeFilterOptions: Merge = overwrite; -export const mergeUiParams: Merge = overwrite; -export const mergeSourceParams: Merge = overwrite; -export const mergeFilterParams: Merge = overwrite; - -export type ContextCallback = - | string - | ((denops: Denops) => Promise>); - -export type ContextCallbacks = { - global: ContextCallback; - filetype: Record; - buffer: Record; -}; +export const mergeUiParams: Merge = overwrite; +export const mergeSourceParams: Merge = overwrite; +export const mergeFilterParams: Merge = overwrite; export function foldMerge( merge: Merge, @@ -416,21 +407,16 @@ function isNegligible(older: World, newer: World): boolean { older.event === newer.event; } -export class ContextBuilder { +export class ContextBuilderImpl implements ContextBuilder { #lastWorld: World = initialWorld(); #custom: Custom = new Custom(); - // Re-export for denops.dispatcher - async _cacheWorld(denops: Denops, event: DdcEvent): Promise { - return await cacheWorld(denops, event); - } - async createContext( denops: Denops, event: DdcEvent, options: UserOptions = {}, ): Promise<[boolean, Context, DdcOptions]> { - const world = await this._cacheWorld(denops, event); + const world = await cacheWorld(denops, event); const old = this.#lastWorld; this.#lastWorld = world; let skip = false; @@ -458,9 +444,9 @@ export class ContextBuilder { const userOptions = await this.#getUserOptions(denops, world, options); - await this.validate(denops, "options", userOptions, defaultDdcOptions()); + await this.#validate(denops, "options", userOptions, defaultDdcOptions()); for (const key in userOptions.sourceOptions) { - await this.validate( + await this.#validate( denops, "sourceOptions", userOptions.sourceOptions[key], @@ -513,11 +499,11 @@ export class ContextBuilder { return this.#custom.buffer; } async getCurrent(denops: Denops): Promise { - const world = await this._cacheWorld(denops, "Manual"); + const world = await cacheWorld(denops, "Manual"); return this.#getUserOptions(denops, world); } - async validate( + async #validate( denops: Denops, name: string, options: Record, diff --git a/denops/ddc/ddc.ts b/denops/ddc/ddc.ts index dab5c4b..c2dd3b4 100644 --- a/denops/ddc/ddc.ts +++ b/denops/ddc/ddc.ts @@ -1,6 +1,5 @@ import type { - BaseUi, - BaseUiParams, + BaseParams, CallbackContext, Context, DdcEvent, @@ -14,7 +13,7 @@ import type { } from "./types.ts"; import { defaultDummy } from "./context.ts"; import type { Loader } from "./loader.ts"; -import { defaultUiOptions } from "./base/ui.ts"; +import { type BaseUi, defaultUiOptions } from "./base/ui.ts"; import { defaultSourceOptions } from "./base/source.ts"; import { callFilterFilter, @@ -46,9 +45,9 @@ type DdcResult = { }; export class Ddc { - currentUi: BaseUi | undefined = undefined; + currentUi: BaseUi | undefined = undefined; currentUiOptions: UiOptions = defaultUiOptions(); - currentUiParams: BaseUiParams = defaultDummy(); + currentUiParams: BaseParams = defaultDummy(); visibleUi = false; #loader: Loader; @@ -134,7 +133,6 @@ export class Ddc { denops, context, onCallback, - this.#loader, options, o, p, @@ -411,10 +409,8 @@ export class Ddc { return true; } - const [ui, uiOptions, uiParams] = await getUi( + const [ui, uiOptions, uiParams] = await this.#getUi( denops, - this.#loader, - this, context, options, ); @@ -511,10 +507,8 @@ export class Ddc { return; } - const [ui, uiOptions, uiParams] = await getUi( + const [ui, uiOptions, uiParams] = await this.#getUi( denops, - this.#loader, - this, context, options, ); @@ -542,10 +536,8 @@ export class Ddc { context: Context, options: DdcOptions, ) { - const [ui, uiOptions, uiParams] = await getUi( + const [ui, uiOptions, uiParams] = await this.#getUi( denops, - this.#loader, - this, context, options, ); @@ -573,10 +565,8 @@ export class Ddc { return true; } - const [ui, uiOptions, uiParams] = await getUi( + const [ui, uiOptions, uiParams] = await this.#getUi( denops, - this.#loader, - this, context, options, ); @@ -596,6 +586,35 @@ export class Ddc { }) : true; } + + async #getUi( + denops: Denops, + context: Context, + options: DdcOptions, + ): Promise<[BaseUi | undefined, UiOptions, BaseParams]> { + const [ui, uiOptions, uiParams] = await getUi( + denops, + this.#loader, + options, + ); + if (ui !== this.currentUi) { + // UI is changed + if (this.currentUi) { + await this.currentUi.hide({ + denops, + context, + options, + uiOptions: this.currentUiOptions, + uiParams: this.currentUiParams, + }); + } + + this.currentUi = ui; + this.currentUiOptions = uiOptions; + this.currentUiParams = uiParams; + } + return [ui, uiOptions, uiParams]; + } } function formatAbbr(word: string, abbr: string | undefined): string { diff --git a/denops/ddc/ext.ts b/denops/ddc/ext.ts index 19bce66..7e4e6cd 100644 --- a/denops/ddc/ext.ts +++ b/denops/ddc/ext.ts @@ -1,10 +1,5 @@ import type { - BaseFilter, - BaseFilterParams, - BaseSource, - BaseSourceParams, - BaseUi, - BaseUiParams, + BaseParams, Context, DdcGatherItems, DdcItem, @@ -32,11 +27,10 @@ import { mergeUiParams, } from "./context.ts"; import type { Loader } from "./loader.ts"; -import type { Ddc } from "./ddc.ts"; import { isDdcCallbackCancelError } from "./callback.ts"; -import { defaultUiOptions } from "./base/ui.ts"; -import { defaultSourceOptions } from "./base/source.ts"; -import { defaultFilterOptions } from "./base/filter.ts"; +import { type BaseUi, defaultUiOptions } from "./base/ui.ts"; +import { type BaseSource, defaultSourceOptions } from "./base/source.ts"; +import { type BaseFilter, defaultFilterOptions } from "./base/filter.ts"; import { printError } from "./utils.ts"; import type { Denops } from "jsr:@denops/std@~7.1.0"; @@ -46,16 +40,12 @@ import { deadline } from "jsr:@std/async@~1.0.1/deadline"; export async function getUi( denops: Denops, loader: Loader, - ddu: Ddc, - context: Context, options: DdcOptions, -): Promise< - [ - BaseUi | undefined, - UiOptions, - BaseUiParams, - ] -> { +): Promise<[ + BaseUi | undefined, + UiOptions, + BaseParams, +]> { if (options.ui.length === 0) { return [ undefined, @@ -82,27 +72,6 @@ export async function getUi( const [uiOptions, uiParams] = uiArgs(options, ui); - if (ui !== ddu.currentUi) { - // UI is changed - - if (ddu.currentUi) { - // Hide current UI - await ddu.currentUi.hide({ - denops, - context, - options, - uiOptions: ddu.currentUiOptions, - uiParams: ddu.currentUiParams, - }); - - ddu.visibleUi = false; - } - - ddu.currentUi = ui; - ddu.currentUiOptions = uiOptions; - ddu.currentUiParams = uiParams; - } - await checkUiOnInit(ui, denops, uiOptions, uiParams); return [ui, uiOptions, uiParams]; @@ -115,9 +84,9 @@ export async function getSource( userSource: UserSource, ): Promise< [ - BaseSource | undefined, + BaseSource | undefined, SourceOptions, - BaseSourceParams, + BaseParams, ] > { const name = source2Name(userSource); @@ -149,7 +118,6 @@ export async function getSource( denops, sourceOptions, sourceParams, - loader, ); return [source, sourceOptions, sourceParams]; @@ -162,9 +130,9 @@ export async function getFilter( userFilter: UserFilter, ): Promise< [ - BaseFilter | undefined, + BaseFilter | undefined, FilterOptions, - BaseFilterParams, + BaseParams, ] > { const name = filter2Name(userFilter); @@ -224,7 +192,6 @@ export async function getPreviewer( options, sourceOptions, sourceParams, - loader, item, previewContext, }); @@ -363,7 +330,6 @@ export async function onEvent( await callSourceOnEvent( source, denops, - loader, context, onCallback, options, @@ -421,7 +387,6 @@ export async function onCompleteDone( await callSourceOnCompleteDone( source, denops, - loader, context, onCallback, options, @@ -431,10 +396,10 @@ export async function onCompleteDone( ); } -function uiArgs( +function uiArgs( options: DdcOptions, ui: BaseUi, -): [UiOptions, BaseUiParams] { +): [UiOptions, BaseParams] { const o = foldMerge( mergeUiOptions, defaultUiOptions, @@ -448,13 +413,13 @@ function uiArgs( } function sourceArgs< - Params extends BaseSourceParams, + Params extends BaseParams, UserData extends unknown, >( source: BaseSource | null, options: DdcOptions, userSource: UserSource | null, -): [SourceOptions, BaseSourceParams] { +): [SourceOptions, BaseParams] { // Convert type if (typeof userSource === "string") { userSource = { @@ -485,12 +450,12 @@ function sourceArgs< } function filterArgs< - Params extends BaseFilterParams, + Params extends BaseParams, >( filter: BaseFilter, options: DdcOptions, userFilter: UserFilter, -): [FilterOptions, BaseFilterParams] { +): [FilterOptions, BaseParams] { // Convert type if (typeof userFilter === "string") { userFilter = { @@ -521,10 +486,10 @@ function filterArgs< } async function checkUiOnInit( - ui: BaseUi, + ui: BaseUi, denops: Denops, uiOptions: UiOptions, - uiParams: BaseUiParams, + uiParams: BaseParams, ) { if (ui.isInitialized) { return; @@ -548,11 +513,10 @@ async function checkUiOnInit( } async function checkSourceOnInit( - source: BaseSource, + source: BaseSource, denops: Denops, sourceOptions: SourceOptions, - sourceParams: BaseSourceParams, - loader: Loader, + sourceParams: BaseParams, ) { if (source.isInitialized) { return; @@ -563,7 +527,6 @@ async function checkSourceOnInit( denops, sourceOptions, sourceParams, - loader, }); source.isInitialized = true; @@ -585,10 +548,10 @@ async function checkSourceOnInit( } async function checkFilterOnInit( - filter: BaseFilter, + filter: BaseFilter, denops: Denops, filterOptions: FilterOptions, - filterParams: BaseFilterParams, + filterParams: BaseParams, ) { if (filter.isInitialized) { return; @@ -612,14 +575,13 @@ async function checkFilterOnInit( } async function callSourceOnEvent( - source: BaseSource, + source: BaseSource, denops: Denops, - loader: Loader, context: Context, onCallback: OnCallback, options: DdcOptions, sourceOptions: SourceOptions, - sourceParams: BaseSourceParams, + sourceParams: BaseParams, ) { if (!source.events?.includes(context.event)) { return; @@ -633,7 +595,6 @@ async function callSourceOnEvent( options, sourceOptions, sourceParams, - loader, }); } catch (e: unknown) { if (isDdcCallbackCancelError(e)) { @@ -649,12 +610,11 @@ async function callSourceOnEvent( } async function callSourceOnCompleteDone< - Params extends BaseSourceParams, + Params extends BaseParams, UserData extends unknown, >( source: BaseSource, denops: Denops, - loader: Loader, context: Context, onCallback: OnCallback, options: DdcOptions, @@ -670,7 +630,6 @@ async function callSourceOnCompleteDone< options, sourceOptions, sourceParams, - loader, // This is preventing users from accessing the internal properties. // deno-lint-ignore no-explicit-any userData: userData as any, @@ -689,21 +648,19 @@ async function callSourceOnCompleteDone< } export async function callSourceGetCompletePosition( - source: BaseSource, + source: BaseSource, denops: Denops, context: Context, onCallback: OnCallback, - loader: Loader, options: DdcOptions, sourceOptions: SourceOptions, - sourceParams: BaseSourceParams, + sourceParams: BaseParams, ): Promise { try { return await source.getCompletePosition({ denops, context, onCallback, - loader, options, sourceOptions, sourceParams, @@ -724,7 +681,7 @@ export async function callSourceGetCompletePosition( } export async function callSourceGather< - Params extends BaseSourceParams, + Params extends BaseParams, UserData extends unknown, >( source: BaseSource, @@ -773,13 +730,13 @@ export async function callSourceGather< } async function callFilterOnEvent( - filter: BaseFilter, + filter: BaseFilter, denops: Denops, context: Context, onCallback: OnCallback, options: DdcOptions, filterOptions: FilterOptions, - filterParams: BaseFilterParams, + filterParams: BaseParams, ) { if (!filter.events?.includes(context.event)) { return; @@ -808,14 +765,14 @@ async function callFilterOnEvent( } export async function callFilterFilter( - filter: BaseFilter, + filter: BaseFilter, denops: Denops, context: Context, onCallback: OnCallback, options: DdcOptions, sourceOptions: SourceOptions, filterOptions: FilterOptions, - filterParams: BaseFilterParams, + filterParams: BaseParams, completeStr: string, items: Item[], ): Promise { diff --git a/denops/ddc/loader.ts b/denops/ddc/loader.ts index b205474..f64f896 100644 --- a/denops/ddc/loader.ts +++ b/denops/ddc/loader.ts @@ -1,15 +1,13 @@ import type { - BaseFilter, - BaseFilterParams, - BaseSource, - BaseSourceParams, - BaseUi, - BaseUiParams, + BaseParams, DdcExtType, FilterName, SourceName, UiName, } from "./types.ts"; +import type { BaseSource } from "./base/source.ts"; +import type { BaseFilter } from "./base/filter.ts"; +import type { BaseUi } from "./base/ui.ts"; import { isDenoCacheIssueError } from "./utils.ts"; import { mods } from "./_mods.js"; @@ -24,9 +22,9 @@ import { toFileUrl } from "jsr:@std/path@~1.0.2/to-file-url"; import { Lock } from "jsr:@core/asyncutil@~1.1.1/lock"; export class Loader { - #uis: Record> = {}; - #sources: Record> = {}; - #filters: Record> = {}; + #uis: Record> = {}; + #sources: Record> = {}; + #filters: Record> = {}; #aliases: Record> = { ui: {}, source: {}, @@ -134,13 +132,13 @@ export class Loader { getAlias(type: DdcExtType, name: string): string { return this.#aliases[type][name]; } - getUi(name: UiName): BaseUi { + getUi(name: UiName): BaseUi { return this.#uis[name]; } - getSource(name: SourceName): BaseSource { + getSource(name: SourceName): BaseSource { return this.#sources[name]; } - getFilter(name: FilterName): BaseFilter { + getFilter(name: FilterName): BaseFilter { return this.#filters[name]; } diff --git a/denops/ddc/types.ts b/denops/ddc/types.ts index 5e57d05..9b03009 100644 --- a/denops/ddc/types.ts +++ b/denops/ddc/types.ts @@ -1,18 +1,7 @@ +import type { Denops } from "jsr:@denops/std@~7.1.0"; import type { AutocmdEvent } from "jsr:@denops/std@~7.1.0/autocmd"; -import type { BaseUiParams } from "./base/ui.ts"; -import type { BaseSourceParams } from "./base/source.ts"; -import type { BaseFilterParams } from "./base/filter.ts"; -export { BaseConfig } from "./base/config.ts"; -export { BaseUi } from "./base/ui.ts"; -export type { BaseUiParams } from "./base/ui.ts"; -export { BaseSource } from "./base/source.ts"; -export type { BaseSourceParams } from "./base/source.ts"; -export { BaseFilter } from "./base/filter.ts"; -export type { BaseFilterParams } from "./base/filter.ts"; -export type { Denops } from "jsr:@denops/std@~7.1.0"; - -export { ContextBuilder } from "./context.ts"; +export type BaseParams = Record; export type DdcExtType = "ui" | "source" | "filter"; @@ -37,16 +26,43 @@ export type Context = { nextInput: string; }; +export type ContextCallback = + | string + | ((denops: Denops) => Promise>); + +export type ContextCallbacks = { + global: ContextCallback; + filetype: Record; + buffer: Record; +}; + +export interface ContextBuilder { + getGlobal(): Partial; + getFiletype(): Record>; + getContext(): ContextCallbacks; + getBuffer(): Record>; + getCurrent(denops: Denops): Promise>; + setGlobal(options: Partial): void; + setFiletype(ft: string, options: Partial): void; + setBuffer(bufnr: number, options: Partial): void; + setContextGlobal(callback: ContextCallback): void; + setContextFiletype(callback: ContextCallback, ft: string): void; + setContextBuffer(callback: ContextCallback, bufnr: number): void; + patchGlobal(options: Partial): void; + patchFiletype(ft: string, options: Partial): void; + patchBuffer(bufnr: number, options: Partial): void; +} + export type UserSource = SourceName | { name: SourceName; options?: Partial; - params?: Partial; + params?: Partial; }; export type UserFilter = FilterName | { name: FilterName; options?: Partial; - params?: Partial; + params?: Partial; }; export type DdcOptions = { @@ -55,16 +71,16 @@ export type DdcOptions = { backspaceCompletion: boolean; cmdlineSources: UserSource[] | Record; filterOptions: Record>; - filterParams: Record>; + filterParams: Record>; hideOnEvents: boolean; postFilters: UserFilter[]; sourceOptions: Record>; - sourceParams: Record>; + sourceParams: Record>; sources: UserSource[]; specialBufferCompletion: boolean; ui: UiName; uiOptions: Record>; - uiParams: Record>; + uiParams: Record>; }; export type UserOptions = Record;