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

When a block-referenced task is made complete, it is completed after rewriting the contents of another task. #688

Closed
1 task done
0skgc opened this issue May 25, 2022 · 27 comments · Fixed by #1780
Closed
1 task done
Assignees
Labels
scope: data integrity Problems that may cause loss or corruption of user data type: bug Something isn't working

Comments

@0skgc
Copy link

0skgc commented May 25, 2022

Expected Behavior

When a block-referenced task is made complete, the correct task is completed.

Current Behavior

When a block-referenced task is made complete, it is completed after rewriting the contents of another task.

Steps to Reproduce

Complete task2 referenced by ref task2 with Live Preview of the following Markdown

## Category1 
- [ ] task1

## Category 2
- [ ] task2 ^ca47c7

---
- ref task2 ![[#^ca47c7]]
  1. before

screen1

  1. after

screen2

Context (Environment)

  • Obsidian version: 0.14.13
  • Tasks version: 1.5.1
  • I have tried it with all other plugins disabled and the error still occurs

Possible Solution

No idea.

@schemar
Copy link
Collaborator

schemar commented May 26, 2022

Thank you for the report @0skgc! We need to investigate further, but I assume that the indexes of lists and sections are different within the reference. If that's the case, a fix would be tricky, as that is done by obsidian.

@schemar schemar added the type: bug Something isn't working label May 26, 2022
@claremacrae
Copy link
Collaborator

claremacrae commented May 26, 2022

This is brilliant @0skgc - Thank you very much indeed for reporting it.

I have very occasionally seen issues similar to this, where the completed task is written in the wrong file or wrong task, over-writing and losing another task.

I have been trying hard to reproduce it, when it happens, but never got a reproduction. So I assumed it was some weird timing thing.

With this setup:

  • the default theme
  • Tasks 1.5.1 as the only plugin
  • Obsidian 0.14.13 on Mac
  • Your exact file saved on my machine
  • And viewed both in Source Mode and Reading mode..

Then when I mark the task as complete via the footnote transclusion in Reading mode, I consistently completed task2 overwriting task1.

@claremacrae
Copy link
Collaborator

Then when I mark the task as complete via the footnote in Reading mode, I consistently completed task2 overwriting task1.

Here is a demo:

Issue.688.Repro.mov

@claremacrae
Copy link
Collaborator

I don't use footnotes, but this exactly matches my experience of what has happened, but for me it's rare and when I spot it, I have never been able to reproduce it.

So I am super happy there is a reproduction now!

@claremacrae
Copy link
Collaborator

Oh, it's not a footnote, it's a transclusion.

@0skgc
Copy link
Author

0skgc commented May 26, 2022

At first I thought it was a rare occurrence too, but I have confirmed that it is reproducible, so I am reporting it.
I'm glad to be able to contribute to obsidian-tasks, as I make the most use of it among the obsidian plugins.

@claremacrae
Copy link
Collaborator

No it's not a transclusion. I give up!

@schemar
Copy link
Collaborator

schemar commented May 29, 2022

I thought it was a transclusion. Why is it not?

@claremacrae
Copy link
Collaborator

You're right! Sorry!

@claremacrae
Copy link
Collaborator

I have been able to reproduce this with both these versions of Tasks:

  • 1.5.1
  • 1.6.0

@claremacrae
Copy link
Collaborator

Just to capture what I've done so far to investigate this, and some possible areas to look at.

Display of debug info about tasks

I wanted to be able to see the section and line numbers for tasks, especially those displayed at the bottom of the file.

In 220cbb4 I adjusted the display of tasks to include:

[sectionStart/sectionIndex | path | precedingHeader]

Which are:

    /** Line number where the section starts that contains this task. */
    public readonly sectionStart: number;

    /** The index of the nth task in its section. */
    public readonly sectionIndex: number;

    public readonly path: string;

    public readonly precedingHeader: string | null;

It's very much experimental. It breaks the display

What the results seem to show

image

  1. Task.sectionStart - the section line numbers are 1-based, whereas Task.sectionIndex is 0-based
  2. When rendering tasks in Reading Mode, the task header is null
  3. Don't worry about the ^ca47c7 being rendered wrongly, it's because of the extra text I appended after it
  4. Note that in the embedded task does not have any information about location. (I experimented by adding some lines, and the 2 indices were always 0)
  5. In the results of a tasks block, the two section numbers are valid ...
  6. In the results of a tasks block, the heading is known too

@claremacrae
Copy link
Collaborator

There is useful information in CONTRIBUTING's 'How does Tasks handle status changes?'.

I need to confirm next which of those 4 routes is used when clicking on the embedded task.

Some thoughts/questions:

  1. Not relevant to this issue, but the timing comments may explain why I have occasionally found the wrong task being updated and not been able to reproduce it:

/**
* Replaces the original task with one or more new tassk.
*
* If you pass more than one replacement task, all subsequent tasks in the same
* section must be re-rendered, as their section indexes change. Assuming that
* this is done faster than user interaction in practice.
*/
export const replaceTaskWithTasks = async ({
originalTask,
newTasks,
}: {

  1. I think there may be a case here to add some consistency-checking to ensure that the found line has the same content as the task being replaced.

obsidian-tasks/src/File.ts

Lines 138 to 145 in 17c9545

if (line.includes(globalFilter)) {
if (sectionIndex === originalTask.sectionIndex) {
listItem = listItemCache;
break;
}
sectionIndex++;
}

  1. I wonder if there should be a default value of the two section indices that differs from zero. I think that what is happening in this case is that the embedded task has indices 0,0 and so the first task in the file is being overwritten.

@claremacrae
Copy link
Collaborator

I've confirmed that when I click on the block-referenced task to complete it, the code invoked is the call handler in Task.toLi() and both the section numbers for the task are zeroes.

There are a few calls to Task.fromLine() that look like this:

    const task = Task.fromLine({
        line,
        path,
        sectionStart: 0, // We don't need this to toggle it here in the editor.
        sectionIndex: 0, // We don't need this to toggle it here in the editor.
        precedingHeader: null, // We don't need this to toggle it here in the editor.
    });

I wonder if there any that I could adjust so that they pass in the line numbers, and then this might fix the finding of the correct task to complete.

I'm going to have a break now - will leave this for a while, in case anything that I've said so far prompts any suggestions from @schemar ...

@schemar
Copy link
Collaborator

schemar commented Aug 2, 2022

If I recall correctly, Tasks used line numbers (instead of sections) at some point. I moved to sections in order to utilize the (then) new Obsidian API for the markdown post processor. If I remember right, it is more performant than going line-by-line. Or maybe it is more accurate. Or possibly both 😅

Adding line numbers to tasks should be easy. Would they be available for block-referenced tasks? If it was the line number from the editor, it wouldn't be the line number in the file.

Potentially, this is something that should be discussed with lishid. Shouldn't Obsidian's API provide the correct section data?

However, I am not sure line numbers would solve the timing issue? They would still change while the user interacts if you add more than one task.

@quanru
Copy link

quanru commented Jan 3, 2023

If I recall correctly, Tasks used line numbers (instead of sections) at some point. I moved to sections in order to utilize the (then) new Obsidian API for the markdown post processor. If I remember right, it is more performant than going line-by-line. Or maybe it is more accurate. Or possibly both 😅

Adding line numbers to tasks should be easy. Would they be available for block-referenced tasks? If it was the line number from the editor, it wouldn't be the line number in the file.

Potentially, this is something that should be discussed with lishid. Shouldn't Obsidian's API provide the correct section data?

However, I am not sure line numbers would solve the timing issue? They would still change while the user interacts if you add more than one task.

cc @lishid

@quanru
Copy link

quanru commented Jan 4, 2023

I've confirmed that when I click on the block-referenced task to complete it, the code invoked is the call handler in Task.toLi() and both the section numbers for the task are zeroes.

There are a few calls to Task.fromLine() that look like this:

    const task = Task.fromLine({
        line,
        path,
        sectionStart: 0, // We don't need this to toggle it here in the editor.
        sectionIndex: 0, // We don't need this to toggle it here in the editor.
        precedingHeader: null, // We don't need this to toggle it here in the editor.
    });

I wonder if there any that I could adjust so that they pass in the line numbers, and then this might fix the finding of the correct task to complete.

I'm going to have a break now - will leave this for a while, in case anything that I've said so far prompts any suggestions from @schemar ...

hi, it seems still not work right? @schemar

@claremacrae
Copy link
Collaborator

@quanru Will you please stop pinging people.

Nothing has changed in Tasks, so I would expect this still to be broken.

Have you tested this and found it to work? If so, please add information like what version of Obsidian and Tasks you are using.

@quanru
Copy link

quanru commented Jan 4, 2023

@claremacrae Sorry! I tested this and found it still to be broken. My version information:
Obsidian version: 1.1.9
Tasks version: 1.22.0
OS: mac os 13.1

before:
image
after:
image

@claremacrae
Copy link
Collaborator

Yes, that is expected. There is currently a lot of effort going in to Tasks right now, but not in this area.

@BluBloos
Copy link
Contributor

working on solving this right now and I admit I'm having a little bit of fun 😄

Screen.Recording.2023-02-12.at.3.20.34.PM.mov

@BluBloos
Copy link
Contributor

BluBloos commented Feb 12, 2023

As schemar mentioned in a previous comment,

Shouldn't Obsidian's API provide the correct section data?

I'm afraid there may indeed be a shortcoming in what Ob API is offering us.

To summarize the issue:

  1. The InlineRenderer class acts on some generated HTML from some .md. This rendering applies when in "Reading" mode or in an inline markdown block.
  2. The inline markdown blocks can be created with ![[noteName]], ![[#someHeader]], and ![[^foo]].
  3. InlineRenderer loops through all list items in the HTML to create a list of tasks (Task[]). The sectionStart for each Task comes direct from a call to myMarkdownPostProcessorContext.getSectionInfo(taskHTMLelem).
  4. the section information returned appears to be relative to the beginning of the inline markdown block, as opposed to the beginning of the source note from which the inline markdown block is sourcing its content.
  5. in the particular repro example used until now for the issue, the section information of (0,0) is returned since within the inline markdown block the task is inside the first section and is the first item. replaceTaskWithTasks sees this section information and replaces our toggled task into the very first task in the source file.
  6. in the screencap I posted just above, I click the second task and thus replacing the second overall task within the source file.
  7. All cases of ![[noteName]] work OK since the inline markdown block begins at the beginning of the source note.

  1. Therefore the troublesome cases are ![[#someHeader]] and ![[^foo]].

Without adjustments to the Ob API (unless someone can ideate a workaround), I suggest it be documented as a "known issue" ...

@claremacrae
Copy link
Collaborator

I feel the solution to this is the issue elsewhere about not overwriting a task line whose content differs from the task being completed...

Then, at least the user's data will not be corrupted.

The other solution is to document an example carefully and log an issue in the Forum. Doing so well enough to get the issue implemented takes several hours of effort in my experience.

@claremacrae
Copy link
Collaborator

I do agree that documenting the issue would be OK too.

Thanks very much for investigating this!

@schemar
Copy link
Collaborator

schemar commented Feb 13, 2023

One work around could be to ignore clicks if the task is within a referenced section, if it's possible to identify that. Or maybe show a warning instead of handling the task. 🤔

@claremacrae
Copy link
Collaborator

There is precedent for producing a warning.

https://obsidian-tasks-group.github.io/obsidian-tasks/getting-started/#limitations-and-warnings
The one beginning
Tasks can read tasks that are inside blockquotes or [Obsidian’s built-in callouts](https://help.obsidian.md/How+to/Use+callouts).

image

(There have been some grumbles from users, as it is obtrusive and cannot be disabled)

@BluBloos
Copy link
Contributor

I feel the solution to this is the issue elsewhere about not overwriting a task line whose content differs from the task being completed
...
The other solution is to document an example carefully and log an issue in the Forum. Doing so well enough to get the issue implemented takes several hours of effort in my experience.
...
I do agree that documenting the issue would be OK too.

I think all three of these should be done?

The first is a fix right now to ensure no data loss. The latter is to let people know about the limitation. And the middle one is the long-term solution to "resolve" the limitation.

I'm hoping that in pursuit of the middle one - getting more information about the issue, will reveal some sort of workaround or in fact that the Ob API does have what is needed ...

One work around could be to ignore clicks if the task is within a referenced section

What I meant by workaround was a different way to implement the feature (mark a task that is rendered in an inline markdown view as done)

@claremacrae
Copy link
Collaborator

Hi @BluBloos, thanks very much for all your efforts on this. I am really happy to be guided by your recommendations.

claremacrae added a commit to claremacrae/obsidian-tasks that referenced this issue Mar 4, 2023
@claremacrae claremacrae moved this from 📋 Backlog to 🔖 Ready in Tasks (Obsidian plugin) Roadmap Mar 5, 2023
@claremacrae claremacrae self-assigned this Mar 5, 2023
@claremacrae claremacrae moved this from 🔖 Ready to 🏗 In progress in Tasks (Obsidian plugin) Roadmap Mar 21, 2023
claremacrae added a commit that referenced this issue Mar 21, 2023
This fixes #688, in the usual case where the embedded task
only appears once in the file.

It also fixes #1680, again so long as the task line only
appears once in the file.
@github-project-automation github-project-automation bot moved this from 🏗 In progress to ✅ Done in Tasks (Obsidian plugin) Roadmap Mar 21, 2023
@claremacrae claremacrae moved this from ✅ Done to 🎉 Released in Tasks (Obsidian plugin) Roadmap Mar 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope: data integrity Problems that may cause loss or corruption of user data type: bug Something isn't working
Projects
Status: 🎉 Released
Development

Successfully merging a pull request may close this issue.

5 participants