Skip to content

Commit d35195f

Browse files
committed
feat: use $EDITOR for creating notes with content
1 parent 5e6d702 commit d35195f

File tree

3 files changed

+117
-33
lines changed

3 files changed

+117
-33
lines changed

src/commands/notes/create.ts

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
1-
import {CommentPermissionType, CreateNoteOptions, NotePermissionRole} from '@hackmd/api/dist/type'
2-
import {CliUx, Flags} from '@oclif/core'
1+
import {
2+
CommentPermissionType,
3+
CreateNoteOptions,
4+
NotePermissionRole,
5+
} from "@hackmd/api/dist/type";
6+
import { CliUx, Flags } from "@oclif/core";
7+
import * as fs from "fs";
38

4-
import HackMDCommand from '../../command'
5-
import {commentPermission, noteContent, notePermission, noteTitle} from '../../flags'
6-
import {safeStdinRead} from '../../utils'
9+
import HackMDCommand from "../../command";
10+
import {
11+
commentPermission,
12+
noteContent,
13+
notePermission,
14+
noteTitle,
15+
} from "../../flags";
16+
import { safeStdinRead, temporaryMD } from "../../utils";
17+
import openEditor from "../../openEditor";
718

8-
export default class Create extends HackMDCommand {
9-
static description = 'Create a note'
19+
export default class CreateCommand extends HackMDCommand {
20+
static description = "Create a note";
1021

1122
static examples = [
1223
"notes create --content='# A new note' --readPermission=owner --writePermission=owner --commentPermission=disabled",
@@ -15,54 +26,73 @@ export default class Create extends HackMDCommand {
1526
────────────────────── ──────────────────────────────── ────────────────────── ────────
1627
raUuSTetT5uQbqQfLnz9lA A new note gvfz2UB5THiKABQJQnLs6Q null`,
1728

18-
'Or you can pipe content via Unix pipeline:',
19-
'cat README.md | hackmd-cli notes create'
20-
]
29+
"Or you can pipe content via Unix pipeline:",
30+
"cat README.md | hackmd-cli notes create",
31+
];
2132

2233
static flags = {
23-
help: Flags.help({char: 'h'}),
34+
help: Flags.help({ char: "h" }),
2435
title: noteTitle(),
2536
content: noteContent(),
2637
readPermission: notePermission(),
2738
writePermission: notePermission(),
2839
commentPermission: commentPermission(),
40+
editor: Flags.boolean({
41+
char: "e",
42+
description: "create note with $EDITOR",
43+
}),
2944
...CliUx.ux.table.flags(),
30-
}
45+
};
3146

3247
async run() {
33-
const {flags} = await this.parse(Create)
34-
const pipeString = safeStdinRead()
48+
const { flags } = await this.parse(CreateCommand);
49+
const pipeString = safeStdinRead();
3550

3651
const options: CreateNoteOptions = {
3752
title: flags.title,
3853
content: pipeString || flags.content,
3954
readPermission: flags.readPermission as NotePermissionRole,
4055
writePermission: flags.writePermission as NotePermissionRole,
41-
commentPermission: flags.commentPermission as CommentPermissionType
56+
commentPermission: flags.commentPermission as CommentPermissionType,
57+
};
58+
59+
if (flags.editor) {
60+
try {
61+
const mdFile = temporaryMD();
62+
await openEditor(mdFile);
63+
64+
options.content = fs.readFileSync(mdFile).toString();
65+
} catch (e) {
66+
this.error(e as Error);
67+
}
4268
}
4369

4470
try {
45-
const APIClient = await this.getAPIClient()
46-
const note = await APIClient.createNote(options)
71+
const APIClient = await this.getAPIClient();
72+
const note = await APIClient.createNote(options);
4773

48-
CliUx.ux.table([note], {
49-
id: {
50-
header: 'ID',
51-
},
52-
title: {},
53-
userPath: {
54-
header: 'User path'
74+
CliUx.ux.table(
75+
[note],
76+
{
77+
id: {
78+
header: "ID",
79+
},
80+
title: {},
81+
userPath: {
82+
header: "User path",
83+
},
84+
teamPath: {
85+
header: "Team path",
86+
},
5587
},
56-
teamPath: {
57-
header: 'Team path'
88+
{
89+
printLine: this.log.bind(this),
90+
...flags,
5891
}
59-
}, {
60-
printLine: this.log.bind(this),
61-
...flags
62-
})
92+
);
6393
} catch (e) {
64-
this.log('Create note failed')
65-
this.error(e as Error)
94+
this.log("Create note failed");
95+
this.error(e as Error);
6696
}
6797
}
6898
}

src/openEditor.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { spawn, ChildProcess } from "child_process";
2+
3+
interface EditorOptions {
4+
editor?: string;
5+
}
6+
7+
export function openEditor(
8+
file: string,
9+
opts: EditorOptions = {}
10+
): Promise<void> {
11+
return new Promise((resolve, reject) => {
12+
const editor = getEditor(opts.editor);
13+
const args = editor.split(/\s+/);
14+
const bin = args.shift();
15+
16+
if (!bin) {
17+
reject(new Error("Editor binary not found"));
18+
return;
19+
}
20+
21+
console.debug(`Opening ${file} with ${bin} ${args.join(" ")}`);
22+
23+
const ps: ChildProcess = spawn(bin, [...args, file], { stdio: "inherit" });
24+
25+
ps.on("exit", (code: number, sig: NodeJS.Signals) => {
26+
resolve();
27+
});
28+
29+
ps.on("error", (err: Error) => {
30+
reject(err);
31+
});
32+
});
33+
}
34+
35+
function getEditor(editor?: string): string {
36+
return (
37+
editor || process.env.VISUAL || process.env.EDITOR || getDefaultEditor()
38+
);
39+
}
40+
41+
function getDefaultEditor(): string {
42+
return /^win/.test(process.platform) ? "notepad" : "vim";
43+
}
44+
45+
export default openEditor;

src/utils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import fs from 'fs'
2-
import {homedir} from 'os'
2+
import {homedir, tmpdir} from 'os'
33
import * as path from 'path'
44

55
export function getConfigFilePath() {
@@ -32,3 +32,12 @@ export function safeStdinRead() {
3232
} catch {}
3333
return result
3434
}
35+
36+
// generate temporary markdown file in /tmp directory
37+
export function temporaryMD() {
38+
const tmpDir = tmpdir();
39+
const filename = `temp_${Math.random().toString(36).substring(2)}.md`;
40+
const filePath = path.join(tmpDir, filename);
41+
42+
return filePath;
43+
}

0 commit comments

Comments
 (0)