11// Copyright (c) jdneo. All rights reserved.
22// Licensed under the MIT license.
33
4- import * as fse from "fs-extra " ;
4+ import * as _ from "lodash " ;
55import * as path from "path" ;
66import * as unescapeJS from "unescape-js" ;
77import * as vscode from "vscode" ;
@@ -11,7 +11,7 @@ import { leetCodeChannel } from "../leetCodeChannel";
1111import { leetCodeExecutor } from "../leetCodeExecutor" ;
1212import { leetCodeManager } from "../leetCodeManager" ;
1313import { IProblem , IQuickItemEx , languages , ProblemState } from "../shared" ;
14- import { getNodeIdFromFile } from "../utils/problemUtils" ;
14+ import { genFileExt , genFileName , getNodeIdFromFile } from "../utils/problemUtils" ;
1515import { DialogOptions , DialogType , openSettingsEditor , promptForOpenOutputChannel , promptForSignIn , promptHintMessage } from "../utils/uiUtils" ;
1616import { getActiveFilePath , selectWorkspaceFolder } from "../utils/workspaceUtils" ;
1717import * as wsl from "../utils/wslUtils" ;
@@ -137,27 +137,38 @@ async function showProblemInternal(node: IProblem): Promise<void> {
137137 }
138138
139139 const leetCodeConfig : vscode . WorkspaceConfiguration = vscode . workspace . getConfiguration ( "leetcode" ) ;
140- let outDir : string = await selectWorkspaceFolder ( ) ;
141- if ( ! outDir ) {
140+ const workspaceFolder : string = await selectWorkspaceFolder ( ) ;
141+ if ( ! workspaceFolder ) {
142142 return ;
143143 }
144144
145- let relativePath : string = ( leetCodeConfig . get < string > ( "outputFolder" , "" ) ) . trim ( ) ;
146- if ( relativePath ) {
147- relativePath = await resolveRelativePath ( relativePath , node , language ) ;
148- if ( ! relativePath ) {
145+ const outputFolder : string = leetCodeConfig . get < string > ( "outputFolder" , "" ) . trim ( ) ;
146+
147+ const fileFolder : string = leetCodeConfig
148+ . get < string > ( `filePath.${ language } .folder` , leetCodeConfig . get < string > ( `filePath.default.folder` , outputFolder ) )
149+ . trim ( ) ;
150+ const fileName : string = leetCodeConfig
151+ . get < string > (
152+ `filePath.${ language } .filename` ,
153+ leetCodeConfig . get < string > ( `filePath.default.filename` , genFileName ( node , language ) ) ,
154+ )
155+ . trim ( ) ;
156+
157+ let finalPath : string = path . join ( workspaceFolder , fileFolder , fileName ) ;
158+
159+ if ( finalPath ) {
160+ finalPath = await resolveRelativePath ( finalPath , node , language ) ;
161+ if ( ! finalPath ) {
149162 leetCodeChannel . appendLine ( "Showing problem canceled by user." ) ;
150163 return ;
151164 }
152165 }
153166
154- outDir = path . join ( outDir , relativePath ) ;
155- await fse . ensureDir ( outDir ) ;
167+ finalPath = wsl . useWsl ( ) ? await wsl . toWinPath ( finalPath ) : finalPath ;
156168
157- const originFilePath : string = await leetCodeExecutor . showProblem ( node , language , outDir , leetCodeConfig . get < boolean > ( "showCommentDescription" ) ) ;
158- const filePath : string = wsl . useWsl ( ) ? await wsl . toWinPath ( originFilePath ) : originFilePath ;
169+ await leetCodeExecutor . showProblem ( node , language , finalPath , leetCodeConfig . get < boolean > ( "showCommentDescription" ) ) ;
159170 await Promise . all ( [
160- vscode . window . showTextDocument ( vscode . Uri . file ( filePath ) , { preview : false , viewColumn : vscode . ViewColumn . One } ) ,
171+ vscode . window . showTextDocument ( vscode . Uri . file ( finalPath ) , { preview : false , viewColumn : vscode . ViewColumn . One } ) ,
161172 movePreviewAsideIfNeeded ( node ) ,
162173 promptHintMessage (
163174 "hint.commentDescription" ,
@@ -201,26 +212,49 @@ function parseProblemDecorator(state: ProblemState, locked: boolean): string {
201212}
202213
203214async function resolveRelativePath ( relativePath : string , node : IProblem , selectedLanguage : string ) : Promise < string > {
215+ let tag : string = "" ;
204216 if ( / \$ \{ t a g \} / i. test ( relativePath ) ) {
205- const tag : string | undefined = await resolveTagForProblem ( node ) ;
206- if ( ! tag ) {
207- return "" ;
208- }
209- relativePath = relativePath . replace ( / \$ \{ t a g \} / ig, tag ) ;
217+ tag = ( await resolveTagForProblem ( node ) ) || "" ;
210218 }
211219
212- relativePath = relativePath . replace ( / \$ \{ l a n g u a g e \} / ig, selectedLanguage ) ;
213- relativePath = relativePath . replace ( / \$ \{ d i f f i c u l t y \} / ig, node . difficulty . toLocaleLowerCase ( ) ) ;
214-
215- // Check if there is any unsupported configuration
216- const matchResult : RegExpMatchArray | null = relativePath . match ( / \$ \{ ( .* ?) \} / ) ;
217- if ( matchResult && matchResult . length >= 1 ) {
218- const errorMsg : string = `The config '${ matchResult [ 1 ] } ' is not supported.` ;
219- leetCodeChannel . appendLine ( errorMsg ) ;
220- throw new Error ( errorMsg ) ;
220+ let company : string = "" ;
221+ if ( / \$ \{ c o m p a n y \} / i. test ( relativePath ) ) {
222+ company = ( await resolveCompanyForProblem ( node ) ) || "" ;
221223 }
222224
223- return relativePath ;
225+ return relativePath . replace ( / \$ \{ ( .* ?) \} / g, ( _substring : string , ...args : string [ ] ) => {
226+ const placeholder : string = args [ 0 ] . toLowerCase ( ) . trim ( ) ;
227+ switch ( placeholder ) {
228+ case "id" :
229+ return node . id ;
230+ case "name" :
231+ return node . name ;
232+ case "camelcasename" :
233+ return _ . camelCase ( node . name ) ;
234+ case "pascalcasename" :
235+ return _ . upperFirst ( _ . camelCase ( node . name ) ) ;
236+ case "kebabcasename" :
237+ case "kebab-case-name" :
238+ return _ . kebabCase ( node . name ) ;
239+ case "snakecasename" :
240+ case "snake_case_name" :
241+ return _ . snakeCase ( node . name ) ;
242+ case "ext" :
243+ return genFileExt ( selectedLanguage ) ;
244+ case "language" :
245+ return selectedLanguage ;
246+ case "difficulty" :
247+ return node . difficulty . toLocaleLowerCase ( ) ;
248+ case "tag" :
249+ return tag ;
250+ case "company" :
251+ return company ;
252+ default :
253+ const errorMsg : string = `The config '${ placeholder } ' is not supported.` ;
254+ leetCodeChannel . appendLine ( errorMsg ) ;
255+ throw new Error ( errorMsg ) ;
256+ }
257+ } ) ;
224258}
225259
226260async function resolveTagForProblem ( problem : IProblem ) : Promise < string | undefined > {
@@ -236,3 +270,14 @@ async function resolveTagForProblem(problem: IProblem): Promise<string | undefin
236270 } ,
237271 ) ;
238272}
273+
274+ async function resolveCompanyForProblem ( problem : IProblem ) : Promise < string | undefined > {
275+ if ( problem . companies . length === 1 ) {
276+ return problem . companies [ 0 ] ;
277+ }
278+ return await vscode . window . showQuickPick ( problem . companies , {
279+ matchOnDetail : true ,
280+ placeHolder : "Multiple tags available, please select one" ,
281+ ignoreFocusOut : true ,
282+ } ) ;
283+ }
0 commit comments