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
19 changes: 19 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,25 @@ author: "Yamanaka.J"
---
```

### ```--no-dir```

このフラグを付けることでディレクトリを作成することなく、ファイルを作成します。

```
% note-cli create article --no-dir -t
Create file. 2023-09-30.md

% cat 2023-09-30.md
---
title: ""
tags: []
date: "2023-09-30"
author: ""
---
```

**記事から生成した画像を記事と一緒に管理しやすいようにディレクトリ構造を採用しています。しかし、このディレクトリ構造が不要な場合は```no-dir```フラグを使用することでファイルのみを管理することができます。例えば、個人ブログをmarkdownで書いているなら、その記事の管理に使用することもできるでしょう。**

## create image

```create image```コマンドを実行することで[OGP](https://ogp.me/)画像風の画像を生成することができます。~~画像の生成にはカレントディレクトリに<a href="#configyaml">config.yaml</a>が存在している必要があります。もし、config.yamlが存在していなかった場合はコマンドが失敗します。~~
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,25 @@ author: "Yamanaka.J"
---
```

### ```--no-dir```

Using this flag creates file without creating directory.

```
% note-cli create article --no-dir -t
Create file. 2023-09-30.md

% cat 2023-09-30.md
---
title: ""
tags: []
date: "2023-09-30"
author: ""
---
```

**note-cli uses a directory structure to facilitate managing images generated from articles along with the articles. However, if you do not need this directory structure, you can use the ``no-dir`` flag to manage only files. For example, if you are writing a personal blog in markdown, you may use it to manage your articles.**

## create image

Image like [OGP](https://ogp.me/) can be generated by executing the ```create image``` command.~~The <a href="#configyaml">config.yaml</a> must exist in the current directory to generate images.If config.yaml does not exist, the command will fail.~~
Expand Down
12 changes: 7 additions & 5 deletions cmd/article.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,24 @@ You can also specify the -t(--time) option to make the current timestamp the fil
If nothing is specified, the file is created with a unique file name by UUID.
`,
Args: cobra.NoArgs,
RunE: run.CreateArticleFunc(&timeFlag, &name, &autor),
RunE: run.CreateArticleFunc(&timeFlag, &noDirFlag, &name, &author),
Example: `note-cli create article
note-cli create article --name article-a
note-cli create article -t`,
}

var (
timeFlag bool
name string
autor string
timeFlag bool
name string
author string
noDirFlag bool
)

func init() {
articleCmd.Flags().BoolVarP(&timeFlag, "time", "t", false, "Create directory and file names with the current timestamp")
articleCmd.Flags().StringVarP(&name, "name", "n", "", "Create a directory with the specified name")
articleCmd.Flags().StringVarP(&autor, "author", "a", "", "Author name")
articleCmd.Flags().StringVarP(&author, "author", "a", "", "Author name")
articleCmd.Flags().BoolVar(&noDirFlag, "no-dir", false, "Create an article file without directory.")

articleCmd.MarkFlagsMutuallyExclusive("time", "name")

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
)

require (
github.com/MakeNowJust/heredoc/v2 v2.0.1
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A=
github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/go-rod/rod v0.114.3 h1:gAUT2Bc2wy0tQL5KEet05HNDvmndaHAGCjQ01TB2efA=
github.com/go-rod/rod v0.114.3/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw=
Expand Down
86 changes: 86 additions & 0 deletions internal/file/file_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package file_test

import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"

"github.com/JY8752/note-cli/internal/file"
"github.com/MakeNowJust/heredoc/v2"
)

func TestExist(t *testing.T) {
Expand Down Expand Up @@ -63,3 +66,86 @@ func TestExist(t *testing.T) {
})
}
}

func TestExtract(t *testing.T) {
t.Parallel()

tests := map[string]struct {
content string
start string
end string
want string
wantErr bool
}{
"simple: double quotation": {
content: `"test" xxxxxx`,
start: "\"",
end: "\"",
want: "test",
},
"default: from --- to ---": {
content: heredoc.Doc(`---
title: ""
tags: []
date: "2023-09-30"
author: "Junichi.Y"
---
`),
start: "---",
end: "---",
want: "\n" + heredoc.Doc(`
title: ""
tags: []
date: "2023-09-30"
author: "Junichi.Y"
`),
},
"error: missing start key": {
content: heredoc.Doc(`title: ""
tags: []
date: "2023-09-30"
author: "Junichi.Y"
---
`),
start: "---",
end: "---",
wantErr: true,
},
"error: missing end key": {
content: heredoc.Doc(`---
title: ""
tags: []
date: "2023-09-30"
author: "Junichi.Y"
`),
start: "---",
end: "---",
wantErr: true,
},
}

for name, tt := range tests {
name, tt := name, tt
t.Run(name, func(t *testing.T) {
t.Parallel()
r := strings.NewReader(tt.content)
b, err := file.Extract(r, tt.start, tt.end)

if tt.wantErr && err == nil {
t.Fatal("expect error, but not error")
}
if tt.wantErr && err != nil {
t.Log(err)
return
}

if err != nil {
t.Fatal(err)
}

if !bytes.Equal(b, []byte(tt.want)) {
t.Errorf("extract contents are not expected. act: %s exp: %s", string(b), tt.want)
}
})
}
}
62 changes: 35 additions & 27 deletions internal/run/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"embed"
"encoding/base64"
"errors"
"fmt"
"html/template"
"os"
Expand All @@ -13,6 +12,7 @@ import (

"github.com/JY8752/note-cli/internal/clock"
"github.com/JY8752/note-cli/internal/file"
"github.com/MakeNowJust/heredoc/v2"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
"github.com/go-rod/rod/lib/utils"
Expand All @@ -30,7 +30,7 @@ type Options struct {

type Option func(*Options)

func CreateArticleFunc(timeFlag *bool, name, author *string, options ...Option) RunEFunc {
func CreateArticleFunc(timeFlag, noDirFlag *bool, name, author *string, options ...Option) RunEFunc {
return func(cmd *cobra.Command, args []string) (err error) {
t := *timeFlag
n := *name
Expand All @@ -41,56 +41,65 @@ func CreateArticleFunc(timeFlag *bool, name, author *string, options ...Option)
option(&op)
}

// create directory name
var dirName string
// create target name
var targetName string

// set timestamp in directory name
// set timestamp in targert name
now := clock.Now().Format("2006-01-02")
if t {
dirName = now
targetName = now

counter := 1
for {
if !file.Exist(filepath.Join(op.BasePath, dirName)) {
if !file.Exist(filepath.Join(op.BasePath, targetName)) {
break
}
counter++
dirName = now + "-" + strconv.Itoa(counter)
targetName = now + "-" + strconv.Itoa(counter)
}
}

// set specify directory name
// set specify name in target name
if n != "" {
dirName = n
if file.Exist(filepath.Join(op.BasePath, n)) && !*noDirFlag {
return fmt.Errorf("already exist article directory. name: %s", n)
}
if file.Exist(filepath.Join(op.BasePath, n+".md")) && *noDirFlag {
return fmt.Errorf("already exist article file. name: %s", n)
}
targetName = n
}

// random value since nothing was specified
if !t && n == "" {
if op.DefaultDirName != "" {
dirName = op.DefaultDirName
targetName = op.DefaultDirName
} else {
dirName = uuid.NewString()
targetName = uuid.NewString()
}
}

// mkdir
targetDir := filepath.Join(op.BasePath, dirName)
if err = os.Mkdir(targetDir, 0744); err != nil {
return
}
targetDir := op.BasePath
if !*noDirFlag {
targetDir = filepath.Join(targetDir, targetName)
if err = os.Mkdir(targetDir, 0744); err != nil {
return
}

fmt.Printf("Create directory. %s\n", targetDir)
fmt.Printf("Create directory. %s\n", targetDir)
}

// create markdown file
filePath := filepath.Join(targetDir, fmt.Sprintf("%s.md", dirName))
filePath := filepath.Join(targetDir, fmt.Sprintf("%s.md", targetName))

metadata := fmt.Sprintf(`---
title: ""
tags: []
date: "%s"
author: "%s"
---
`, now, *author)
metadata := heredoc.Docf(`---
title: ""
tags: []
date: "%s"
author: "%s"
---
`, now, *author)

if err = os.WriteFile(filePath, []byte(metadata), 0644); err != nil {
return
Expand Down Expand Up @@ -185,15 +194,14 @@ func CreateImageFunc(templateNo *int16, iconPath, outputPath *string, options ..
if b, err = file.Extract(markdownFile, "---", "---"); err == nil {
break
}
fmt.Println(err.Error())
}
}

if len(b) == 0 {
// If the config could not be loaded, look for config.yaml.
// config.yaml is already obsolete and should be loaded for compatibility.
if b, err = os.ReadFile(filepath.Join(op.BasePath, ConfigFile)); err != nil {
return errors.New("not found article config")
return fmt.Errorf("not found article config. %w", err)
}
}

Expand Down
Loading