11import type { Denops , Entrypoint } from "jsr:@denops/std@^7.3.2" ;
22import { ensurePromise } from "jsr:@core/asyncutil@^1.2.0/ensure-promise" ;
33import { assert , ensure , is } from "jsr:@core/unknownutil@^4.3.0" ;
4- import type { DetailUnit } from "jsr:@vim-fall/core@^0.3.0/item" ;
4+ import type { Detail } from "jsr:@vim-fall/core@^0.3.0/item" ;
55
66import type { PickerParams } from "../custom.ts" ;
77import {
@@ -13,9 +13,14 @@ import {
1313} from "../custom.ts" ;
1414import { isOptions , isPickerParams , isStringArray } from "../util/predicate.ts" ;
1515import { action as buildActionSource } from "../extension/source/action.ts" ;
16- import { Picker } from "../picker.ts" ;
16+ import { Picker , type PickerContext } from "../picker.ts" ;
1717import type { SubmatchContext } from "./submatch.ts" ;
1818import { ExpectedError , withHandleError } from "../error.ts" ;
19+ import {
20+ listPickerSessions ,
21+ loadPickerSession ,
22+ savePickerSession ,
23+ } from "../session.ts" ;
1924
2025let zindex = 50 ;
2126
@@ -32,6 +37,7 @@ export const main: Entrypoint = (denops) => {
3237 await loadUserCustom ( denops ) ;
3338 // Split the command arguments
3439 const [ name , ...sourceArgs ] = ensure ( args , isStringArray ) ;
40+
3541 // Load user custom
3642 const itemPickerParams = getPickerParams ( name ) ;
3743 if ( ! itemPickerParams ) {
@@ -58,14 +64,92 @@ export const main: Entrypoint = (denops) => {
5864 return listPickerNames ( ) . filter ( ( name ) => name . startsWith ( arglead ) ) ;
5965 } ,
6066 ) ,
67+ "picker:resume:command" : withHandleError (
68+ denops ,
69+ async ( filter ) => {
70+ assert ( filter , is . UnionOf ( [ is . String , is . Nullish ] ) ) ;
71+ await loadUserCustom ( denops ) ;
72+ return await resumePicker ( denops , filter ?? "" , {
73+ signal : denops . interrupted ,
74+ } ) ;
75+ } ,
76+ ) ,
77+ "picker:resume:command:complete" : withHandleError (
78+ denops ,
79+ async ( arglead , cmdline , cursorpos ) => {
80+ await loadUserCustom ( denops ) ;
81+ assert ( arglead , is . String ) ;
82+ assert ( cmdline , is . String ) ;
83+ assert ( cursorpos , is . Number ) ;
84+ const sessions = listPickerSessions ( ) ;
85+ if ( cmdline . includes ( "#" ) ) {
86+ // Resume by filter
87+ const [ name ] = arglead . split ( "#" , 2 ) ;
88+ const filteredSessions = name
89+ ? sessions . filter ( ( s ) => s . name === name )
90+ : sessions ;
91+ const candidates = Array . from (
92+ { length : filteredSessions . length } ,
93+ ( _ , i ) => {
94+ return `${ name } #${ i + 1 } ` ;
95+ } ,
96+ ) ;
97+ return candidates . filter ( ( c ) => c . startsWith ( arglead ) ) ;
98+ } else {
99+ // Resume by name
100+ const candidates = sessions . map ( ( s ) => s . name ) ;
101+ return candidates . filter ( ( c ) => c . startsWith ( arglead ) ) ;
102+ }
103+ } ,
104+ ) ,
61105 } ;
62106} ;
63107
64- async function startPicker (
108+ async function resumePicker (
109+ denops : Denops ,
110+ filter : string ,
111+ { signal } : {
112+ signal ?: AbortSignal ;
113+ } = { } ,
114+ ) : Promise < void | true > {
115+ // Parse filter ({name}#{indexFromLatest})
116+ const [ filterName , filterNumberStr = "1" ] = filter . split ( "#" , 2 ) ;
117+ const filterNumber = Number ( filterNumberStr ) ;
118+ const session = await loadPickerSession ( {
119+ name : filterName ,
120+ number : filterNumber ,
121+ } ) ;
122+ if ( ! session ) {
123+ throw new ExpectedError (
124+ `Picker session ${ filterName } #${ filterNumberStr } is not available.` ,
125+ ) ;
126+ }
127+ // Load user custom
128+ const pickerParams = getPickerParams ( session . name ) ;
129+ if ( ! pickerParams ) {
130+ throw new ExpectedError (
131+ `No item picker "${ session . name } " is found. Available item pickers are: ${
132+ listPickerNames ( ) . join ( ", " )
133+ } `,
134+ ) ;
135+ }
136+ const { args, context } = session ;
137+ await startPicker (
138+ denops ,
139+ args ,
140+ pickerParams ,
141+ { signal, context } ,
142+ ) ;
143+ }
144+
145+ async function startPicker < T extends Detail > (
65146 denops : Denops ,
66- args : string [ ] ,
67- pickerParams : PickerParams < DetailUnit , string > ,
68- { signal } : { signal ?: AbortSignal } = { } ,
147+ args : readonly string [ ] ,
148+ pickerParams : PickerParams < T , string > ,
149+ { signal, context } : {
150+ signal ?: AbortSignal ;
151+ context ?: PickerContext < T > ;
152+ } = { } ,
69153) : Promise < void | true > {
70154 await using stack = new AsyncDisposableStack ( ) ;
71155 const setting = getSetting ( ) ;
@@ -74,6 +158,7 @@ async function startPicker(
74158 ...setting ,
75159 ...pickerParams ,
76160 zindex,
161+ context,
77162 } ) ,
78163 ) ;
79164 zindex += Picker . ZINDEX_ALLOCATION ;
@@ -93,6 +178,13 @@ async function startPicker(
93178 stack . defer ( ( ) => {
94179 zindex -= Picker . ZINDEX_ALLOCATION ;
95180 } ) ;
181+ stack . defer ( async ( ) => {
182+ await savePickerSession ( {
183+ name : pickerParams . name ,
184+ args,
185+ context : itemPicker . context ,
186+ } ) ;
187+ } ) ;
96188
97189 stack . use ( await itemPicker . open ( denops , { signal } ) ) ;
98190 while ( true ) {
@@ -155,7 +247,7 @@ async function startPicker(
155247 pickerParams,
156248 } ,
157249 ...resultItem ,
158- } as const satisfies SubmatchContext ;
250+ } as const satisfies SubmatchContext < T > ;
159251 if ( await ensurePromise ( action . invoke ( denops , actionParams , { signal } ) ) ) {
160252 // Picker should not be closed
161253 continue ;
0 commit comments