Skip to content

Commit 4eda9db

Browse files
luginfluginfpbek
authored
New note namer (#292)
* custom syntax new-note-namer * fix new note namer * simplify interface * add extra dialog for more versability * adding a readme with full instructions * trigger new CI * lint: format file Signed-off-by: Patrizio Bekerle <patrizio@bekerle.com> * We're making the new-note-namer script upgrade-safe for existing users. The code and README are updated with backward-compatible migration logic for the renamed heading setting. * run prettier on README --------- Signed-off-by: Patrizio Bekerle <patrizio@bekerle.com> Co-authored-by: luginf <alan@luginf> Co-authored-by: Patrizio Bekerle <patrizio@bekerle.com>
1 parent b2eb63b commit 4eda9db

3 files changed

Lines changed: 151 additions & 36 deletions

File tree

new-note-namer/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# New note namer
2+
3+
Sets the note title and file name at creation time, with optional dialogs for each field.
4+
Especially useful when the _Allow note file name to be different from note title_ option is enabled in QOwnNotes.
5+
6+
## Settings
7+
8+
| Setting | Description |
9+
| ------------------------------------------ | ----------------------------------------------------------------------------------- |
10+
| **Show a dialog to define the note title** | If checked, a dialog asks for a custom title (pre-filled with the search term). |
11+
| **Show a dialog to define the file name** | If checked, a dialog asks for a custom file name (pre-filled with the search term). |
12+
| **Heading style** | Format applied to the title: ATX (`# Title`), Setext (`Title / =====`), or Custom. |
13+
| **Custom heading – opening tag** | Text inserted before the title (Custom style only). |
14+
| **Custom heading – closing tag** | Text inserted after the title (Custom style only). |
15+
16+
The two dialog options are independent: each defaults to the search term, regardless of the other.
17+
18+
## Behaviour
19+
20+
| Source | Dialog: note title | Dialog: file name | Title | File name |
21+
| ---------------- | ------------------ | ----------------- | ---------------------------- | ------------------------------------------- |
22+
| Search "foo" ||| `# foo` | `foo` |
23+
| Search "foo" ||| dialog pre-filled with `foo` | `foo` (search term, independent from title) |
24+
| Search "foo" ||| `# foo` | dialog pre-filled with `foo` |
25+
| Search "foo" ||| dialog pre-filled with `foo` | dialog pre-filled with `foo` |
26+
| Menu (no search) ||| dialog (no pre-fill) | = entered title |
27+
| Menu (no search) ||| dialog (no pre-fill) | dialog pre-filled with entered title |
28+
29+
> **Note:** the `n:` search prefix (name-only filter) is automatically stripped from the note name.
30+
31+
## Tips
32+
33+
- Leave both dialogs unchecked for a fully automatic workflow: create a note directly from the search bar with one keypress.
34+
- Check only _file name_ to keep the search term as the title but write a longer or different file name.
35+
- Check only _title_ to write a custom heading while keeping the file name equal to the search term.
36+
- The heading style applies in all cases, including when no dialog is shown.
37+
- All settings require a **script engine reload** to take effect after being changed.
38+
39+
## Upgrading from v0.0.2
40+
41+
v0.0.2 had a single boolean setting **Underline heading** that chose between ATX (`# Title`) and Setext (`Title / =====`).
42+
This was replaced by the **Heading style** selection in v0.0.3.
43+
44+
Your stored preference is migrated automatically:
45+
46+
| v0.0.2 setting | Effective heading style after upgrade |
47+
| ------------------- | -------------------------------------------------------------- |
48+
| Unchecked (default) | ATX (`# Title`) — no change |
49+
| Checked | Setext (`Title / =====`) — preserved via the deprecated toggle |
50+
51+
The deprecated **Underline heading (deprecated)** entry remains visible in the script settings so QOwnNotes can still read your stored value.
52+
Once you have set **Heading style** to your preferred option you can safely uncheck the deprecated toggle.

new-note-namer/info.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"name": "New note namer",
33
"identifier": "new-note-namer",
44
"script": "new-note-namer.qml",
5-
"authors": ["@diegovskytl", "@Mystechry"],
5+
"authors": ["@diegovskytl", "@Mystechry", "@luginf"],
66
"platforms": ["linux", "macos", "windows"],
7-
"version": "0.0.2",
7+
"version": "0.0.4",
88
"minAppVersion": "17.06.2",
9-
"description": "Enables a dialog window (or two) so the user can choose the note title and file name at the moment of creation. <br> Specially useful when the 'Allow note file name to be different to note title. \n No more cumbersome renaming :)"
9+
"description": "Enables a dialog window (or two, or even none) so the user can choose the note title and file name at the moment of creation, or simply use the search term for the filename and title of the note with custom formattings. <br><br> Specially useful when the 'Allow note file name to be different to note title. \n No more cumbersome renaming :)"
1010
}

new-note-namer/new-note-namer.qml

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,126 @@ import QOwnNotesTypes 1.0
77
Avoids cumbersome renaming and title editing.
88
*/
99
QtObject {
10+
property bool extraDialogForTitle
1011
property bool extraDialogForFileName
12+
property string headingStyle
13+
property string _searchTerm: ""
14+
property string customHeadingOpen
15+
property string customHeadingClose
16+
property bool underlineHeading // deprecated — kept so existing stored settings still load
1117
property variant settingsVariables: [
18+
{
19+
'identifier': 'extraDialogForTitle',
20+
'name': 'Show a dialog to define the note title',
21+
'description': 'If checked, ask for a custom note title.',
22+
'type': 'boolean',
23+
'default': 'false'
24+
},
1225
{
1326
'identifier': 'extraDialogForFileName',
14-
'name': 'Extra dialog for note title',
15-
'description': 'Show an additional dialog window so user can write a file name different to the note title.',
27+
'name': 'Show a dialog to define the file name',
28+
'description': 'If checked, ask for a custom file name.',
1629
'type': 'boolean',
1730
'default': 'false'
1831
},
32+
{
33+
'identifier': 'headingStyle',
34+
'name': 'Heading style',
35+
'description': 'Title format for new notes.',
36+
'type': 'selection',
37+
'default': '0',
38+
'items': {
39+
'0': 'ATX Markdown heading (# Title)',
40+
'1': 'Setext Markdown heading (Title / =====)',
41+
'2': 'Custom heading (opening and closing tags)'
42+
}
43+
},
44+
{
45+
'identifier': 'customHeadingOpen',
46+
'name': 'Custom heading – opening tag',
47+
'description': 'Text inserted before the note name (only used when heading style is "Custom").',
48+
'type': 'string',
49+
'default': ''
50+
},
51+
{
52+
'identifier': 'customHeadingClose',
53+
'name': 'Custom heading – closing tag',
54+
'description': 'Text inserted after the note name (only used when heading style is "Custom").',
55+
'type': 'string',
56+
'default': ''
57+
},
1958
{
2059
'identifier': 'underlineHeading',
21-
'name': 'Underline heading',
22-
'description': 'Highlight the first line by underlining it with =, if not checked, use a preceding # instead.',
60+
'name': 'Underline heading (deprecated)',
61+
'description': 'Deprecated: use "Heading style" above instead. Kept so that users upgrading from v0.0.2 automatically keep their Setext-heading preference without needing to change settings.',
2362
'type': 'boolean',
2463
'default': 'false'
2564
},
2665
]
27-
property bool underlineHeading
2866

29-
function handleNewNoteHeadlineHook(note) {
30-
var newName = newNamer("New note", "New note title", "Title");
31-
script.log(note.fileCreated);
32-
script.log(note.fileLastModified);
33-
34-
if (underlineHeading) {
35-
return newName + "\n" + "=".repeat(newName.length);
67+
function handleNewNoteHeadlineHook(headline) {
68+
// 'headline' is a plain string (the search term or default text), not a Note object.
69+
// Strip QOwnNotes search filter prefixes (e.g. "n:" for name-only search).
70+
_searchTerm = headline.replace(/^n:/i, "");
71+
var name;
72+
if (extraDialogForTitle || _searchTerm === "") {
73+
// Show dialog: pre-fill with the search term if available, otherwise a placeholder.
74+
name = newNamer("New note", "New note title", _searchTerm !== "" ? _searchTerm : "Title");
3675
} else {
37-
return "# " + newName;
76+
// If already provided (search term or QOwnNotes own dialog), use it directly.
77+
name = _searchTerm;
3878
}
79+
return buildHeadline(name);
3980
}
40-
function handleNoteTextFileNameHook(note) {
41-
script.log("note name: " + note.name);
42-
script.log("file name: " + note.fileName);
43-
script.log(note.fileCreated);
44-
script.log(note.fileLastModified);
45-
46-
var noteLines = note.noteText.split("\n");
47-
var firstLine = noteLines[0];
48-
var noteTitle = firstLine.slice(2); // Remove the preceding "# "
49-
if (underlineHeading) {
50-
// Underlined headings use the entire first line
51-
noteTitle = firstLine;
81+
// Migration helper: underlineHeading=true from v0.0.2 maps to Setext ("1").
82+
// headingStyle "1" or "2" set explicitly always wins.
83+
function effectiveHeadingStyle() {
84+
if (headingStyle === "0" && underlineHeading) {
85+
return "1";
5286
}
53-
54-
script.log("note title: " + noteTitle);
55-
56-
// right when a note is created, the fileCreated property value is 'Invald Date'
57-
// this blocks the hook to further change the note file name if the note title is changed
87+
return headingStyle;
88+
}
89+
function buildHeadline(name) {
90+
var style = effectiveHeadingStyle();
91+
if (style === "2") {
92+
return customHeadingOpen + name + customHeadingClose;
93+
}
94+
if (style === "1") {
95+
return name + "\n" + "=".repeat(name.length);
96+
}
97+
return "# " + name; // "0" (ATX) or unset
98+
}
99+
function extractTitle(noteText) {
100+
var firstLine = (noteText || "").split("\n")[0];
101+
var style = effectiveHeadingStyle();
102+
if (style === "2") {
103+
var t = firstLine.slice(customHeadingOpen.length);
104+
var closeLen = customHeadingClose.length;
105+
if (closeLen > 0 && t.slice(-closeLen) === customHeadingClose) {
106+
t = t.slice(0, t.length - closeLen);
107+
}
108+
return t;
109+
}
110+
if (style === "1") {
111+
return firstLine; // setext: first line is the bare title
112+
}
113+
return firstLine.slice(2); // ATX: remove "# "
114+
}
115+
function handleNoteTextFileNameHook(note) {
116+
// right when a note is created, the fileCreated property value is 'Invalid Date'
117+
// this blocks the hook from further changing the note file name if the note title is changed
58118
if (note.fileCreated != "Invalid Date") {
59119
return "";
60120
}
61121

122+
// Default file name: search term if available, otherwise derived from the title.
123+
var defaultName = _searchTerm !== "" ? _searchTerm : extractTitle(note.noteText);
124+
62125
if (extraDialogForFileName) {
63-
return newNamer("New note", "New file name", "File name");
64-
} else {
65-
return noteTitle;
126+
return newNamer("New note", "New file name", defaultName);
66127
}
128+
129+
return defaultName;
67130
}
68131
function init() {
69132
script.log("New-note-namer active");

0 commit comments

Comments
 (0)