22// Licensed under the MIT license.
33
44import * as fse from "fs-extra" ;
5+ import * as path from "path" ;
56import * as vscode from "vscode" ;
67import { LeetCodeNode } from "../explorer/LeetCodeNode" ;
8+ import { leetCodeChannel } from "../leetCodeChannel" ;
79import { leetCodeExecutor } from "../leetCodeExecutor" ;
810import { leetCodeManager } from "../leetCodeManager" ;
911import { IProblem , IQuickItemEx , languages , ProblemState } from "../shared" ;
@@ -16,15 +18,15 @@ export async function showProblem(node?: LeetCodeNode): Promise<void> {
1618 if ( ! node ) {
1719 return ;
1820 }
19- await showProblemInternal ( node . id ) ;
21+ await showProblemInternal ( node ) ;
2022}
2123
2224export async function searchProblem ( ) : Promise < void > {
2325 if ( ! leetCodeManager . getUser ( ) ) {
2426 promptForSignIn ( ) ;
2527 return ;
2628 }
27- const choice : IQuickItemEx < string > | undefined = await vscode . window . showQuickPick (
29+ const choice : IQuickItemEx < IProblem > | undefined = await vscode . window . showQuickPick (
2830 parseProblemsToPicks ( list . listProblems ( ) ) ,
2931 {
3032 matchOnDetail : true ,
@@ -37,7 +39,7 @@ export async function searchProblem(): Promise<void> {
3739 await showProblemInternal ( choice . value ) ;
3840}
3941
40- async function showProblemInternal ( id : string ) : Promise < void > {
42+ async function showProblemInternal ( node : IProblem ) : Promise < void > {
4143 try {
4244 const leetCodeConfig : vscode . WorkspaceConfiguration = vscode . workspace . getConfiguration ( "leetcode" ) ;
4345 let defaultLanguage : string | undefined = leetCodeConfig . get < string > ( "defaultLanguage" ) ;
@@ -49,9 +51,21 @@ async function showProblemInternal(id: string): Promise<void> {
4951 return ;
5052 }
5153
52- const outDir : string = await selectWorkspaceFolder ( ) ;
54+ let outDir : string = await selectWorkspaceFolder ( ) ;
55+ let relativePath : string = ( leetCodeConfig . get < string > ( "outputFolder" ) || "" ) . trim ( ) ;
56+ const matchResult : RegExpMatchArray | null = relativePath . match ( / \$ \{ ( .* ?) \} / ) ;
57+ if ( matchResult ) {
58+ const resolvedPath : string | undefined = await resolveRelativePath ( matchResult [ 1 ] . toLocaleLowerCase ( ) , node , language ) ;
59+ if ( ! resolvedPath ) {
60+ leetCodeChannel . appendLine ( "Showing problem canceled by user." ) ;
61+ return ;
62+ }
63+ relativePath = resolvedPath ;
64+ }
65+
66+ outDir = path . join ( outDir , relativePath ) ;
5367 await fse . ensureDir ( outDir ) ;
54- const result : string = await leetCodeExecutor . showProblem ( id , language , outDir ) ;
68+ const result : string = await leetCodeExecutor . showProblem ( node . id , language , outDir ) ;
5569 const reg : RegExp = / \* S o u r c e C o d e : \s * ( .* ) / ;
5670 const match : RegExpMatchArray | null = result . match ( reg ) ;
5771 if ( match && match . length >= 2 ) {
@@ -76,17 +90,17 @@ async function showProblemInternal(id: string): Promise<void> {
7690 }
7791 }
7892 } catch ( error ) {
79- await promptForOpenOutputChannel ( "Failed to fetch the problem information . Please open the output channel for details." , DialogType . error ) ;
93+ await promptForOpenOutputChannel ( "Failed to show the problem. Please open the output channel for details." , DialogType . error ) ;
8094 }
8195}
8296
83- async function parseProblemsToPicks ( p : Promise < IProblem [ ] > ) : Promise < Array < IQuickItemEx < string > > > {
84- return new Promise ( async ( resolve : ( res : Array < IQuickItemEx < string > > ) => void ) : Promise < void > => {
85- const picks : Array < IQuickItemEx < string > > = ( await p ) . map ( ( problem : IProblem ) => Object . assign ( { } , {
97+ async function parseProblemsToPicks ( p : Promise < IProblem [ ] > ) : Promise < Array < IQuickItemEx < IProblem > > > {
98+ return new Promise ( async ( resolve : ( res : Array < IQuickItemEx < IProblem > > ) => void ) : Promise < void > => {
99+ const picks : Array < IQuickItemEx < IProblem > > = ( await p ) . map ( ( problem : IProblem ) => Object . assign ( { } , {
86100 label : `${ parseProblemDecorator ( problem . state , problem . locked ) } ${ problem . id } .${ problem . name } ` ,
87101 description : "" ,
88102 detail : `AC rate: ${ problem . passRate } , Difficulty: ${ problem . difficulty } ` ,
89- value : problem . id ,
103+ value : problem ,
90104 } ) ) ;
91105 resolve ( picks ) ;
92106 } ) ;
@@ -102,3 +116,28 @@ function parseProblemDecorator(state: ProblemState, locked: boolean): string {
102116 return locked ? "$(lock) " : "" ;
103117 }
104118}
119+
120+ async function resolveRelativePath ( value : string , node : IProblem , selectedLanguage : string ) : Promise < string | undefined > {
121+ switch ( value ) {
122+ case "tag" :
123+ if ( node . tags . length === 1 ) {
124+ return node . tags [ 0 ] ;
125+ }
126+ return await vscode . window . showQuickPick (
127+ node . tags ,
128+ {
129+ matchOnDetail : true ,
130+ placeHolder : "Multiple tags available, please select one" ,
131+ ignoreFocusOut : true ,
132+ } ,
133+ ) ;
134+ case "language" :
135+ return selectedLanguage ;
136+ case "difficulty" :
137+ return node . difficulty ;
138+ default :
139+ const errorMsg : string = `The config '${ value } ' is not supported.` ;
140+ leetCodeChannel . appendLine ( errorMsg ) ;
141+ throw new Error ( errorMsg ) ;
142+ }
143+ }
0 commit comments