Skip to content

Commit

Permalink
Merge pull request #72 from Milly/fast-redraw
Browse files Browse the repository at this point in the history
Fast redraw
  • Loading branch information
Shougo authored Jul 27, 2023
2 parents aee0267 + 0bfe23c commit 0320297
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 38 deletions.
127 changes: 89 additions & 38 deletions denops/ddu/ddu.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
assertEquals,
basename,
deferred,
Denops,
echo,
equal,
Expand Down Expand Up @@ -86,6 +87,14 @@ type ItemActions = {
actions: Record<string, unknown>;
};

type RedrawOptions = {
/**
* NOTE: Set restoreItemState to true if redraw without regather because
* item's states reset to gathered.
*/
restoreItemState?: boolean;
};

export class Ddu {
private loader: Loader;
private gatherStates: Record<string, GatherState> = {};
Expand All @@ -97,7 +106,9 @@ export class Ddu {
private quitted = false;
private cancelledToRefresh = false;
private abortController = new AbortController();
private redrawLock = new Lock(0);
private uiRedrawLock = new Lock(0);
private waitRedrawComplete?: Promise<void>;
private scheduledRedrawOptions?: RedrawOptions;
private startTime = 0;
private expandedPaths = new Set<string[]>();
private searchPath: TreePath = "";
Expand Down Expand Up @@ -179,7 +190,7 @@ export class Ddu {

if (this.searchPath) {
// Redraw only without regather items.
return this.redraw(denops, true);
return this.redraw(denops, { restoreItemState: true });
}

// UI Redraw only
Expand All @@ -188,7 +199,7 @@ export class Ddu {
await uiRedraw(
denops,
this,
this.redrawLock,
this.uiRedrawLock,
ui,
uiOptions,
uiParams,
Expand Down Expand Up @@ -297,7 +308,8 @@ export class Ddu {

// Initialize UI window
if (!this.options.sync) {
await this.redraw(denops);
// Do not await here
this.redraw(denops);
}

await Promise.all(
Expand Down Expand Up @@ -327,44 +339,41 @@ export class Ddu {
return;
}

// Start gather asynchronously
const gatherItems = this.gatherItems(
denops,
index,
source,
sourceOptions,
sourceParams,
this.loader,
0,
);

// Call "onRefreshItems" hooks
const filters = sourceOptions.matchers.concat(
sourceOptions.sorters,
).concat(sourceOptions.converters);
for (const userFilter of filters) {
await Promise.all(filters.map(async (userFilter) => {
const [filter, filterOptions, filterParams] = await this.getFilter(
denops,
userFilter,
);
if (!filter || !filter.onRefreshItems) {
continue;
}

await filter.onRefreshItems({
await filter?.onRefreshItems?.({
denops,
filterOptions,
filterParams,
});
}
}));

// Get path option, or current directory instead if it is empty
const path = sourceOptions.path.length > 0
? sourceOptions.path
: await fn.getcwd(denops);

let prevLength = state.items.length;

for await (
const newItems of this.gatherItems(
denops,
index,
source,
sourceOptions,
sourceParams,
this.loader,
0,
)
) {
let path = sourceOptions.path;
if (path === "") {
// Use current directory instead
path = await fn.getcwd(denops) as string;
}
for await (const newItems of gatherItems) {
if (path !== this.context.path) {
if (this.context.path.length > 0) {
this.context.pathHistories.push(this.context.path);
Expand All @@ -374,8 +383,9 @@ export class Ddu {

state.items = state.items.concat(newItems);

if (prevLength !== state.items.length && !this.options.sync) {
await this.redraw(denops);
if (!this.options.sync && prevLength !== state.items.length) {
// Do not await inside loop
this.redraw(denops);
prevLength = state.items.length;
}
}
Expand All @@ -391,6 +401,9 @@ export class Ddu {

if (this.options.sync) {
await this.redraw(denops);
} else {
// Wait complete redraw
await this.waitRedrawComplete;
}
}

Expand Down Expand Up @@ -483,11 +496,49 @@ export class Ddu {
}
}

async redraw(
redraw(
denops: Denops,
opts?: RedrawOptions,
): Promise<void> {
if (this.waitRedrawComplete) {
// Already redrawing, so adding to schedule
this.scheduledRedrawOptions = {
// Override with true
restoreItemState: opts?.restoreItemState ||
this.scheduledRedrawOptions?.restoreItemState,
};
} else {
// Start redraw
const complete = this.waitRedrawComplete = deferred<void>();

const scheduleRunner = async (opts?: RedrawOptions) => {
try {
await this.redrawInternal(denops, opts);

opts = this.scheduledRedrawOptions;
if (opts) {
// Scheduled to redraw
this.scheduledRedrawOptions = undefined;
scheduleRunner(opts);
} else {
// All schedules completed
this.waitRedrawComplete = undefined;
complete.resolve();
}
} catch (e: unknown) {
complete.reject(e);
}
};

scheduleRunner(opts);
}

return this.waitRedrawComplete;
}

private async redrawInternal(
denops: Denops,
// NOTE: Set restoreItemState to true if redraw without regather because
// item's states reset to gathered.
restoreItemState?: boolean,
opts?: RedrawOptions,
): Promise<void> {
// Update current input
this.context.done = true;
Expand Down Expand Up @@ -524,7 +575,7 @@ export class Ddu {
index,
this.input,
);
if (restoreItemState) {
if (opts?.restoreItemState) {
items.forEach((item) => {
if (item.treePath) {
item.__expanded = this.isExpanded(convertTreePath(item.treePath));
Expand Down Expand Up @@ -644,7 +695,7 @@ export class Ddu {
await uiRedraw(
denops,
this,
this.redrawLock,
this.uiRedrawLock,
ui,
uiOptions,
uiParams,
Expand Down Expand Up @@ -1100,7 +1151,7 @@ export class Ddu {
await uiRedraw(
denops,
this,
this.redrawLock,
this.uiRedrawLock,
ui,
uiOptions,
uiParams,
Expand Down Expand Up @@ -1280,7 +1331,7 @@ export class Ddu {
await uiRedraw(
denops,
this,
this.redrawLock,
this.uiRedrawLock,
ui,
uiOptions,
uiParams,
Expand Down Expand Up @@ -1343,7 +1394,7 @@ export class Ddu {
await uiRedraw(
denops,
this,
this.redrawLock,
this.uiRedrawLock,
ui,
uiOptions,
uiParams,
Expand Down
1 change: 1 addition & 0 deletions denops/ddu/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export {
dirname,
SEP as pathsep,
} from "https://deno.land/[email protected]/path/mod.ts";
export { deferred } from "https://deno.land/[email protected]/async/deferred.ts";

0 comments on commit 0320297

Please sign in to comment.