Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected behavior when using hooks.on_all_templates_executed on a blank file #1309

Open
simonalveteg opened this issue Jan 25, 2024 · 22 comments · Fixed by #1369
Open

Unexpected behavior when using hooks.on_all_templates_executed on a blank file #1309

simonalveteg opened this issue Jan 25, 2024 · 22 comments · Fixed by #1369
Labels
bug Something isn't working

Comments

@simonalveteg
Copy link

  • OS: Windows 11
  • Templater version: 2.1.2
  • Obsidian version: 1.5.3
  • Templater settings: default settings with templates folder set to /templates/

Describe the bug
When using the hooks.on_all_templates_executed callback like in the documentation with some text that should get added to the note before the frontmatter is updated:

<%*
tp.hooks.on_all_templates_executed(async () => {
  const file = tp.file.find_tfile(tp.file.path(true));
  await app.fileManager.processFrontMatter(file, (frontmatter) => {
    frontmatter["key"] = "value";
  });
});
%>

TEXT THAT SHOULD STAY

if the note the template is added to is blank (no text, no frontmatter), the text gets added and then removed when the frontmatter is added. By just adding a single character to the note before executing the template, both the text and frontmatter gets added without problem. (There is a pop-up "error" that the file has been modified externally and that it's merging the changes, not sure if that's an issue but you asked about it on discord)

Expected behavior
The text and frontmatter should get added to the note even if the note is completely empty.

Additional context
I've tried running the template above on two windows 11 computers with the same result, and also tried it in a new empty vault with only templater installed. I'm not 100% sure, but I believe that it worked as expected before, since I have a few templates that rely on this method. I don't use them regularly though, and I updated them to use this method last time I needed to use them (when the hook had just gotten added), so it's possible that I'm misremembering or that the notes I tested them on weren't completely empty.

link to message on discord

@simonalveteg simonalveteg added the bug Something isn't working label Jan 25, 2024
Zachatoo added a commit that referenced this issue Feb 2, 2024
@Zachatoo
Copy link
Collaborator

Zachatoo commented Feb 2, 2024

I believe I've fixed this in the latest release, can you verify on your end?

@Zachatoo Zachatoo closed this as completed Feb 2, 2024
@simonalveteg
Copy link
Author

Yes! It works now, thanks!

Zachatoo added a commit that referenced this issue Feb 10, 2024
…ntmatter after creation and tests for properties showing in live preview on insert of template with frontmatter

refs: #1253, #1309
@hjone72
Copy link

hjone72 commented Feb 27, 2024

I'm actually still experiencing this issue. I'm on the latest version of templater.

My templates are structured like this:
image
image

I've tried to isolate the situations that it occurs in and this is what I've found:

Scenario 1:
If I "Create new note from template" and I rely upon the "on_all_templates_executed" hook, I get an error "no such file or directory". This is obviously due to me using templater to move the file.

Should the hook handle that scenario?

My workaround for this scenario is to wrap the entire command within a setTimeout, and even with a 0 as the timeout it all works as expected.

Scenario 2:
If I "Insert template" into a blank document the template is overwritten with nothing but the properties. Even using a super simple text using the exact example from the docs produces the same result.
If you add a single character to the note before inserting the template, everything works as expected.
If you add a really large setTimeout it bypasses the issue too.

Thanks,

Zachatoo added a commit that referenced this issue Mar 2, 2024
…n using `tp.hooks.on_all_templates_executed()`

refs: #1309
@Zachatoo
Copy link
Collaborator

Zachatoo commented Mar 2, 2024

@hjone72

Scenario 1:
How are you moving the file? Is it in one of the templates you're including? If you're moving in a tp.hooks.on_all_templates_executed function, there's no guarantee on the ordering of those functions.
Regardless, I have added a 1ms delay to make it less likely for this to happen.

Scenario 2:
Can you provide a minimum reproducible example that I can test with to make a fix for this?

@HyperEpsilon
Copy link

HyperEpsilon commented Mar 12, 2024

I am still experiencing this bug as well. Obsidian 1.5.8, Templater 2.2.3

This template overrides the text for me if inserted into an empty file

Line 1
Line 2
Line 3
Line 4
Line 5

<%*
tp.hooks.on_all_templates_executed(async () => {
  const file = tp.file.find_tfile(tp.file.path(true));
  await app.fileManager.processFrontMatter(file, (frontmatter) => {
    frontmatter["key"] = Math.random();
  });
});
%>

If a delay is added with await new Promise(resolve => setTimeout(resolve, 3000)) then the template works. I'd guess it's because Obsidian hasn't saved the changes to the file yet, and so considers it an empty file for the time being.

@simonalveteg
Copy link
Author

The issue is back for me as well, when I try to run the same example template as I posted earlier the text once again disappears once the properties have been added.

obsidian version 1.5.12, templater version 2.2.3

@Zachatoo Zachatoo reopened this Apr 15, 2024
@FeralFlora
Copy link

FeralFlora commented Apr 26, 2024

I can also reproduce this issue.

Obsidian: 1.5.12
Installer: 1.5.12
Templater: 2.2.3

Steps to reproduce:

  1. Apply a template to a blank note using the "Open insert template modal"
  2. The note must only have one line! If you add more lines, the issue disappears.
  3. The template must include content and tp.hooks.on_all_templates_executed with some application of app.fileManager.processFrontMatter.

Minimal example template:

## Attendees
- John
- Hendrik
- 
## Agenda
- CallGate  

<%*
tp.hooks.on_all_templates_executed(async () => {
	const file = tp.file.find_tfile(tp.file.path(true));
	await app.fileManager.processFrontMatter(file, (frontmatter) => {
		frontmatter["status"] = "In progress"; // create a new property or update an existing one by name
		frontmatter["Title"] = "New title";
	});
});
-%>

Demo:
Obsidian_WdW5uyVPe0

The "Note.md was modified externally, merging changes automatically" notice does not appear when the issue occurs. When it does, the issue does not occur, as far as I can tell. If you add more than the one aforementioned line, this notice appears, and the note content is not overwritten!

@Zachatoo
Copy link
Collaborator

Zachatoo commented May 5, 2024

Thank you all, I can reproduce this issue and am investigating. I know exactly what line of code I can add to resolve this issue, however it would cause a regression for another issue #1253. I am investigating how I can resolve both of these issues.

Zachatoo added a commit that referenced this issue May 5, 2024
Zachatoo added a commit that referenced this issue May 5, 2024
…pp.fileManager.processFrontMatter` on blank files

refs: #1309
@Zachatoo
Copy link
Collaborator

Zachatoo commented May 5, 2024

Should be fixed in 2.2.4!

@Zachatoo Zachatoo closed this as completed May 5, 2024
@hjone72
Copy link

hjone72 commented May 6, 2024

I'm seeing some very unpredictable behaviour with this change.

EDIT:
I've isolated it down to a race condition while saving a file and creating a new one at the same time. (See image below)

image

The weird part is, once this error occurs Obsidian never recovers. You must reload the app and then everything will work again, until the race condition is triggered and the error occurs.

If I revert back to the previous version of Templater or remove the line await app.vault.append(active_editor.file, ""); then everything works again.

@Zachatoo
Copy link
Collaborator

Zachatoo commented May 8, 2024

Should be fixed in 2.3.0, thanks @johnfromoptus !

@Fred-Vatin
Copy link

Fred-Vatin commented May 10, 2024

Obsidian OS plugin1
1.5.12 Win 10 x64 pro (french) 22H2 v2.3.1

Hi,

It still happens in 2.3.1 when using open insert template modal on an empty file.

Here is a template. The only workaround is to replace hook by setTimeout() with a delay of about 4000 on my system. If less than 1000, bug occurs for sure.

<%*
/* Be sure to switch to edit mode first (live preview)
   It is required so it can insert the template in existing file. */
tp.user.Switch_to_edit_mode();

// start of template construct
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];

if (title.startsWith("Untitled")) { 
  title = await tp.system.prompt("What is the plugin name ?"); 
  await tp.file.rename(title);
}

let repo = await tp.system.prompt("What is the plugin repo URL ?");

setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
  frontmatter["tags"] = defTag;
  frontmatter["repo"] = repo;
  frontmatter["type"] = "plugin";
  })
}, 500) // increase this timeout until the bug goes away

await tp.file.move("Categories/Tutos/Obsidian/Plugins/" + title);
%>
# Description

<% tp.file.cursor(1) %><%* app.workspace.activeLeaf.view.editor?.focus(); %>

# My use

# Shortkeys

| Shortkeys | Actions |
| --------- | ------- |
|           |         |
|           |         |

If use this script version using hook with command create new note from template, I get the opposite: the template content is inserted but not the properties.

<%*
/* Be sure to switch to edit mode first (live preview)
   It is required so it can insert the template in existing file. */
tp.user.Switch_to_edit_mode();

// start of template construct
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];

if (title.startsWith("Untitled")) { 
  title = await tp.system.prompt("What is the plugin name ?"); 
  await tp.file.rename(title);
} 

//don’t insert the title as a tag because it can be long and contains space
//defTag.push(title)

let repo = await tp.system.prompt("What is the plugin repo URL ?");

tp.hooks.on_all_templates_executed(async () => {
  const file = tp.file.find_tfile(tp.file.path(true));
  await app.fileManager.processFrontMatter(file, (frontmatter) => {
	  frontmatter["tags"] = defTag;
	  frontmatter["repo"] = repo;
	  frontmatter["type"] = "plugin";
  });
});

/* setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
  frontmatter["tags"] = defTag;
  frontmatter["repo"] = repo;
  frontmatter["type"] = "plugin";
  })
}, 500) */ // this timeout will prevent a bug when insert the template to an existing file that content only one empty line. When it happens, the note content is deleted. See: https://github.com/SilentVoid13/Templater/issues/1309#issuecomment-2079178033

await tp.file.move("Categories/Tutos/Obsidian/Plugins/" + title);
%>

@FeralFlora
Copy link

@Fred-Vatin I tested your template (with the userscript part removed), and got the same result when inserting into a blank file: The content was lost, and the frontmatter changes stayed. The file was moved as expected.


When I compared your problematic template to my working ones, the main difference was that you had the prompts and renaming outside tp.hooks. If I put all the prompts and such that you have inside tp.hooks.on_all_templates_executed, the content of the note is not lost anymore. I changed it like so:

<%*
tp.hooks.on_all_templates_executed(async () => {
	// start of template construct
	let title = tp.file.title;
	// tags are type of list and are expressed as array
	const defTag = ["Obsidian/Plugin"];
	
	if (title.startsWith("Untitled")) { 
	title = await tp.system.prompt("What is the plugin name ?"); 
	await tp.file.rename(title);
	} 
	//don’t insert the title as a tag because it can be long and contains space
	//defTag.push(title)
	
	let repo = await tp.system.prompt("What is the plugin repo URL ?");
	const file = tp.file.find_tfile(tp.file.path(true));
	await app.fileManager.processFrontMatter(file, (frontmatter) => {
	  frontmatter["tags"] = defTag;
	  frontmatter["repo"] = repo;
	  frontmatter["type"] = "plugin";
	});
});
/* setTimeout(() => {
  app.fileManager.processFrontMatter(tp.config.target_file, frontmatter => {
  frontmatter["tags"] = defTag;
  frontmatter["repo"] = repo;
  frontmatter["type"] = "plugin";
  })
}, 1000); */ // this timeout will prevent a bug when insert the template to an existing file that content only one empty line. When it happens, the note content is deleted. See: https://github.com/SilentVoid13/Templater/issues/1309#issuecomment-2079178033
%>

Actually, moving the renaming part to after tp.hooks also prevented the issue, and the content was not lost. Tp.hooks still executes after the renaming code (see the included logs).

<%*
tp.hooks.on_all_templates_executed(async () => {
	console.log("inside tp.hooks");
	//don’t insert the title as a tag because it can be long and contains space
	//defTag.push(title)
	
	let repo = await tp.system.prompt("What is the plugin repo URL ?");
	const file = tp.file.find_tfile(tp.file.path(true));
	await app.fileManager.processFrontMatter(file, (frontmatter) => {
	  frontmatter["tags"] = defTag;
	  frontmatter["repo"] = repo;
	  frontmatter["type"] = "plugin";
	});
});

// start of template construct
console.log("after tp.hooks");
let title = tp.file.title;
// tags are type of list and are expressed as array
const defTag = ["Obsidian/Plugin"];

if (title.startsWith("Untitled")) { 
  title = await tp.system.prompt("What is the plugin name ?"); 
  await tp.file.rename(title);
} 
%>

@FeralFlora
Copy link

Doesn't matter if you move the file, or whether the content is before the codeblock, or after.

@Fred-Vatin
Copy link

This is the last version that works in any case using tp.hooks and your feedback.

<%*
/* Be sure to switch to edit mode first (live preview)
   It is required so it can insert the template in existing file.
   It must be called first and outside the tp.hooks. */
tp.user.Switch_to_edit_mode();

tp.hooks.on_all_templates_executed(async () => {
// tp.hooks will prevent a bug when insert the template to an existing file that content only one empty line. When it happens, the note content is deleted. See: https://github.com/SilentVoid13/Templater/issues/1309#issuecomment-2079178033
	
	// start of template construct
	let title = tp.file.title;
	// tags are type of list and are expressed as array
	const defTag = ["Obsidian/Plugin"];
	
	if (title.startsWith("Untitled")) { 
	  title = await tp.system.prompt("What is the plugin name ?"); 
	  await tp.file.rename(title);
	} 
	
	//don’t insert the title as a tag because it can be long and contains space
	//defTag.push(title)
	
	let repo = await tp.system.prompt("What is the plugin repo URL ?");
	const file = tp.file.find_tfile(tp.file.path(true));
	
	await app.fileManager.processFrontMatter(file, (frontmatter) => {
	  frontmatter["tags"] = defTag;
	  frontmatter["repo"] = repo;
	  frontmatter["type"] = "plugin";
	});
	
	await tp.file.move("Categories/Tutos/Obsidian/Plugins/" + title);
});
%>
# Description

<% tp.file.cursor(1) %><%* app.workspace.activeLeaf.view.editor?.focus(); %>

# Comment je m’en sers

# Shortkeys

| Shortkeys | Actions |
| --------- | ------- |
|           |         |
|           |         |

Content of my script Switch_to_edit_mode.js:

function switch_to_editmode () {
	/* Be sure to switch to edit mode first (live preview)
		 It is required so it can insert the template in existing file. */
	const view = app.workspace.activeLeaf.getViewState()
	view.state.mode = 'source'
	view.state.source = false
	app.workspace.activeLeaf.setViewState(view)
}
module.exports = switch_to_editmode;

Thanks.

@simonalveteg
Copy link
Author

I'm afraid the issue still exists for me as of 2.3.1. Again using

<%*
tp.hooks.on_all_templates_executed(async () => {
  const file = tp.file.find_tfile(tp.file.path(true));
  await app.fileManager.processFrontMatter(file, (frontmatter) => {
    frontmatter["key"] = "value";
  });
});
%>

TEXT THAT SHOULD STAY

on a new empty file the text that should stay doesn't stay. However, now the text doesn't pop up for half a second before it disappears which it used to do.

@Zachatoo
Copy link
Collaborator

Should be fixed in 2.3.2!

@FeralFlora
Copy link

Should be fixed in 2.3.2!

I re-tested @Fred-Vatin's previously problematic template here, and can confirm that the fix seems to have worked 🎉

@FeralFlora
Copy link

<%*
tp.hooks.on_all_templates_executed(async () => {
  const file = tp.file.find_tfile(tp.file.path(true));
  await app.fileManager.processFrontMatter(file, (frontmatter) => {
    frontmatter["key"] = "value";
  });
});
%>

TEXT THAT SHOULD STAY

on a new empty file the text that should stay doesn't stay. However, now the text doesn't pop up for half a second before it disappears which it used to do.

However, when testing this simple template, the text stays but the frontmatter disappears (which is strange, since @simonalveteg reported that the text would disappear):

Obsidian_b2uxKIFrU5

However, I can't reproduce it reliably. Sometimes, the frontmatter stays, sometimes it disappears.

Here a time where it worked:
Obsidian_DfsLCSiZsD

@FeralFlora
Copy link

But I suppose the above doesn't apply directly to this issue, because the issue is about inserting templates into blank notes. In the above testing, I was creating a new note from a template.

I can't reproduce the issue when inserting the template, so I suppose the fix did work. So it's only creating new notes from templates that is bugging out, sometimes.

@Zachatoo
Copy link
Collaborator

Reverted the fix for this template as it was causing more harm than good, will look into this further when I get a chance.

@alancunha26
Copy link

Still having this issue, any updates?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants