Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ code:
# Available attributes: Id, Slug, Title, Difficulty, Lang, SlugIsMeaningful
# Available functions: lower, upper, trim, padWithZero, toUnderscore
filename_template: '{{ .Id | padWithZero 4 }}{{ if .SlugIsMeaningful }}.{{ .Slug }}{{ end }}'
# Generate question description into a separate file
separate_description_file: false
# Functions that modify the generated code
modifiers:
- name: removeUselessComments
Expand Down
2 changes: 2 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ code:
# Available attributes: Id, Slug, Title, Difficulty, Lang, SlugIsMeaningful
# Available functions: lower, upper, trim, padWithZero, toUnderscore
filename_template: '{{ .Id | padWithZero 4 }}{{ if .SlugIsMeaningful }}.{{ .Slug }}{{ end }}'
# Generate question description into a separate file
separate_description_file: false
# Functions that modify the generated code
modifiers:
- name: removeUselessComments
Expand Down
33 changes: 18 additions & 15 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,25 @@ type Modifier struct {
}

type CodeConfig struct {
Lang string `yaml:"lang" mapstructure:"lang" comment:"Language of code generated for questions: go, python, ... \n(will be override by project config and flag --lang)"`
FilenameTemplate string `yaml:"filename_template" mapstructure:"filename_template" comment:"The default template to generate filename (without extension), e.g. {{.Id}}.{{.Slug}}\nAvailable attributes: Id, Slug, Title, Difficulty, Lang, SlugIsMeaningful\nAvailable functions: lower, upper, trim, padWithZero, toUnderscore"`
Blocks []Block `yaml:"blocks,omitempty" mapstructure:"blocks" comment:"Replace some blocks of the generated code"`
Modifiers []Modifier `yaml:"modifiers,omitempty" mapstructure:"modifiers" comment:"Functions that modify the generated code"`
Go GoConfig `yaml:"go" mapstructure:"go"`
Python BaseLangConfig `yaml:"python3" mapstructure:"python3"`
Cpp BaseLangConfig `yaml:"cpp" mapstructure:"cpp"`
Java BaseLangConfig `yaml:"java" mapstructure:"java"`
Rust BaseLangConfig `yaml:"rust" mapstructure:"rust"`
Lang string `yaml:"lang" mapstructure:"lang" comment:"Language of code generated for questions: go, python, ... \n(will be override by project config and flag --lang)"`
FilenameTemplate string `yaml:"filename_template" mapstructure:"filename_template" comment:"The default template to generate filename (without extension), e.g. {{.Id}}.{{.Slug}}\nAvailable attributes: Id, Slug, Title, Difficulty, Lang, SlugIsMeaningful\nAvailable functions: lower, upper, trim, padWithZero, toUnderscore"`
SeparateDescriptionFile bool `yaml:"separate_description_file" mapstructure:"separate_description_file" comment:"Generate question description into a separate file"`
Blocks []Block `yaml:"blocks,omitempty" mapstructure:"blocks" comment:"Replace some blocks of the generated code"`
Modifiers []Modifier `yaml:"modifiers,omitempty" mapstructure:"modifiers" comment:"Functions that modify the generated code"`
Go GoConfig `yaml:"go" mapstructure:"go"`
Python BaseLangConfig `yaml:"python3" mapstructure:"python3"`
Cpp BaseLangConfig `yaml:"cpp" mapstructure:"cpp"`
Java BaseLangConfig `yaml:"java" mapstructure:"java"`
Rust BaseLangConfig `yaml:"rust" mapstructure:"rust"`
// Add more languages here
}

type BaseLangConfig struct {
OutDir string `yaml:"out_dir" mapstructure:"out_dir"`
FilenameTemplate string `yaml:"filename_template" mapstructure:"filename_template" comment:"Overrides the default code.filename_template"`
Blocks []Block `yaml:"blocks,omitempty" mapstructure:"blocks" comment:"Replace some blocks of the generated code"`
Modifiers []Modifier `yaml:"modifiers,omitempty" mapstructure:"modifiers" comment:"Functions that modify the generated code"`
OutDir string `yaml:"out_dir" mapstructure:"out_dir"`
FilenameTemplate string `yaml:"filename_template" mapstructure:"filename_template" comment:"Overrides the default code.filename_template"`
SeparateDescriptionFile bool `yaml:"separate_description_file,omitempty" mapstructure:"separate_description_file" comment:"Generate question description into a separate file"`
Blocks []Block `yaml:"blocks,omitempty" mapstructure:"blocks" comment:"Replace some blocks of the generated code"`
Modifiers []Modifier `yaml:"modifiers,omitempty" mapstructure:"modifiers" comment:"Functions that modify the generated code"`
}

type GoConfig struct {
Expand Down Expand Up @@ -182,8 +184,9 @@ func Default() *Config {
Author: "Bob",
Language: ZH,
Code: CodeConfig{
Lang: "go",
FilenameTemplate: `{{ .Id | padWithZero 4 }}{{ if .SlugIsMeaningful }}.{{ .Slug }}{{ end }}`,
Lang: "go",
FilenameTemplate: `{{ .Id | padWithZero 4 }}{{ if .SlugIsMeaningful }}.{{ .Slug }}{{ end }}`,
SeparateDescriptionFile: false,
Modifiers: []Modifier{
{Name: "removeUselessComments"},
},
Expand Down
128 changes: 107 additions & 21 deletions lang/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,13 @@ func (l baseLang) LineComment() string {
return l.lineComment
}

func (l baseLang) generateContent(q *leetcode.QuestionData, blocks []config.Block, modifiers []ModifierFunc) (
string,
error,
) {
func (l baseLang) generateCodeContent(
q *leetcode.QuestionData,
baseFilename string,
blocks []config.Block,
modifiers []ModifierFunc,
separateDescriptionFile bool,
) (string, error) {
code := q.GetCodeSnippet(l.Slug())
tmpl := template.New("root")
tmpl.Funcs(
Expand All @@ -121,7 +124,12 @@ func (l baseLang) generateContent(q *leetcode.QuestionData, blocks []config.Bloc
},
},
)
_, err := tmpl.Parse(contentTemplate)
var err error
if separateDescriptionFile {
_, err = tmpl.Parse(withoutDescriptionContentTemplate)
} else {
_, err = tmpl.Parse(defaultContentTemplate)
}
if err != nil {
return "", err
}
Expand Down Expand Up @@ -160,6 +168,33 @@ func (l baseLang) generateContent(q *leetcode.QuestionData, blocks []config.Bloc
return content, nil
}

func (l baseLang) generateCodeFile(
q *leetcode.QuestionData,
baseFilename string,
blocks []config.Block,
modifiers []ModifierFunc,
separateDescriptionFile bool,
) (
FileOutput,
error,
) {
content, err := l.generateCodeContent(
q,
baseFilename,
blocks,
modifiers,
separateDescriptionFile,
)
if err != nil {
return FileOutput{}, err
}
return FileOutput{
Path: baseFilename + l.extension,
Content: content,
Type: CodeFile,
}, nil
}

func (l baseLang) generateTestCases(q *leetcode.QuestionData) string {
cases := q.GetTestCases()
outputs := q.ParseExampleOutputs()
Expand All @@ -182,50 +217,89 @@ func (l baseLang) generateTestCases(q *leetcode.QuestionData) string {
return strings.Join(caseAndOutputs, "\n\n")
}

func (l baseLang) generateDescriptionFile(q *leetcode.QuestionData, baseFilename string) (FileOutput, error) {
tmpl := `# [%s. %s](%s) (%s)
%s`
url := ""
if q.IsContest() {
url = q.ContestUrl()
} else {
url = q.Url()
}
content := fmt.Sprintf(
tmpl,
q.QuestionFrontendId,
q.GetTitle(),
url,
q.Difficulty,
q.GetFormattedContent(),
)
return FileOutput{
Path: baseFilename + ".md",
Content: content,
Type: DocFile,
}, nil
}

func (l baseLang) GeneratePaths(q *leetcode.QuestionData) (*GenerateResult, error) {
filenameTmpl := getFilenameTemplate(q, l)
baseFilename, err := q.GetFormattedFilename(l.slug, filenameTmpl)
if err != nil {
return nil, err
}

file := FileOutput{
code := FileOutput{
Path: baseFilename + l.extension,
Type: CodeFile,
}
files := []FileOutput{code}

if separateDescriptionFile(l) {
files = append(
files, FileOutput{
Path: baseFilename + ".md",
Type: DocFile,
},
)
}

return &GenerateResult{
Question: q,
Lang: l,
Files: []FileOutput{file},
Files: files,
}, nil
}

func (l baseLang) Generate(q *leetcode.QuestionData) (*GenerateResult, error) {
blocks := getBlocks(l)
modifiers, err := getModifiers(l, builtinModifiers)
filenameTmpl := getFilenameTemplate(q, l)
baseFilename, err := q.GetFormattedFilename(l.slug, filenameTmpl)
if err != nil {
return nil, err
}
content, err := l.generateContent(q, blocks, modifiers)

separateDescriptionFile := separateDescriptionFile(l)
blocks := getBlocks(l)
modifiers, err := getModifiers(l, builtinModifiers)
if err != nil {
return nil, err
}

filenameTmpl := getFilenameTemplate(q, l)
baseFilename, err := q.GetFormattedFilename(l.slug, filenameTmpl)
codeFile, err := l.generateCodeFile(q, baseFilename, blocks, modifiers, separateDescriptionFile)
if err != nil {
return nil, err
}
files := []FileOutput{codeFile}

file := FileOutput{
Path: baseFilename + l.extension,
Content: content,
Type: CodeFile,
if separateDescriptionFile {
docFile, err := l.generateDescriptionFile(q, baseFilename)
if err != nil {
return nil, err
}
files = append(files, docFile)
}
return &GenerateResult{
Question: q,
Lang: l,
Files: []FileOutput{file},
Files: files,
}, nil
}

Expand All @@ -249,7 +323,7 @@ func GetGenerator(lang string) (Lang, error) {
return nil, fmt.Errorf("language %s is not supported yet, welcome to send a PR", lang)
}

func getCodeConfig(lang Lang, key string) string {
func getCodeStringConfig(lang Lang, key string) string {
ans := viper.GetString("code." + lang.Slug() + "." + key)
if ans != "" {
return ans
Expand All @@ -261,7 +335,7 @@ func getFilenameTemplate(q *leetcode.QuestionData, gen Lang) string {
if q.IsContest() {
return config.Get().Contest.FilenameTemplate
}
ans := getCodeConfig(gen, "filename_template")
ans := getCodeStringConfig(gen, "filename_template")
if ans != "" {
return ans
}
Expand All @@ -273,7 +347,7 @@ func getOutDir(q *leetcode.QuestionData, lang Lang) string {
return config.Get().Contest.OutDir
}
cfg := config.Get()
outDir := getCodeConfig(lang, "out_dir")
outDir := getCodeStringConfig(lang, "out_dir")
// If outDir is not set, use the language slug as the outDir.
if outDir == "" {
outDir = lang.Slug()
Expand All @@ -282,6 +356,18 @@ func getOutDir(q *leetcode.QuestionData, lang Lang) string {
return outDir
}

func separateDescriptionFile(lang Lang) bool {
ans := viper.Get("code." + lang.Slug() + ".separate_description_file")
if ans != nil {
return ans.(bool)
}
ans = viper.Get("code." + lang.ShortName() + ".separate_description_file")
if ans != nil {
return ans.(bool)
}
return config.Get().Code.SeparateDescriptionFile
}

func generate(q *leetcode.QuestionData) (Lang, *GenerateResult, error) {
cfg := config.Get()
gen, err := GetGenerator(cfg.Code.Lang)
Expand Down
Loading