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

fix: Prevent rare overwrite of wrong line in Reading mode & results blocks #1663

Merged
merged 2 commits into from
Feb 16, 2023
Merged
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
29 changes: 26 additions & 3 deletions src/File.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { MetadataCache, TFile, Vault } from 'obsidian';
import type { ListItemCache } from 'obsidian';

import { getSettings } from './Config/Settings';
import type { Task } from './Task';
import { Task } from './Task';

import { DateFallback } from './DateFallback';
import { Lazy } from './lib/Lazy';

let metadataCache: MetadataCache | undefined;
let vault: Vault | undefined;
Expand All @@ -24,6 +27,10 @@ export const initializeFile = ({
* 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.
*
* In addition, this function is meant to be called with reasonable confidence
* that the {@code originalTask} is unmodified and at the exact same section and
* sectionIdx in the source file it was originally found in. It will fail otherwise.
*/
export const replaceTaskWithTasks = async ({
originalTask,
Expand Down Expand Up @@ -125,10 +132,26 @@ const tryRepetitive = async ({
}

const line = fileLines[listItemCache.position.start.line];

if (line.includes(globalFilter)) {
if (sectionIndex === originalTask.sectionIndex) {
listItem = listItemCache;
const dateFromFileName = new Lazy(() => DateFallback.fromPath(originalTask.path));
claremacrae marked this conversation as resolved.
Show resolved Hide resolved
const taskFromLine = Task.fromLine({
line,
path: originalTask.path,
precedingHeader: originalTask.precedingHeader,
sectionStart: originalTask.sectionStart,
sectionIndex: originalTask.sectionIndex,
Comment on lines +140 to +143
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to leave this as it is, but I feel that because these checks use values from the original task instead of the new line, they are very weak and do not add any value to the checking for whether the two task lines match.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using these fields from originalTask makes sense.

we locate the line with path, sectionStart, and sectionIndex, therefore those are part of the new Task that gets created from the line. The only cause for concern here is precedingHeader as that may change in the interim.

is there something you're saying that I'm not understanding?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there something you're saying that I'm not understanding?

Maybe, or maybe vice versa. Maybe I'm not understanding. And unfortunately the earlier conversations are all hidden now, by being resolved.

I thought that the idea behind calling task.identicalTo() was to check more fields in the two tasks, but it looks to me like one of the tasks is populated from fields from the other task.

So it looks to me like task.identicalTo() is giving a false sense of extra value - and it would probably be safer and clearer to check task.originalMarkdown.

I may later refactor the new code out to a helper function in a file that does not import Obsidian types, to be able to write some tests for it, and explore the behaviour better.

The only cause for concern here is precedingHeader as that may change in the interim.

Yes, that is a concern.

Another concern is a change behind the scenes somehow from this:

## header

- [ ] task 1
- [ ] task 2 - I am the task that will be completed

to this:

## header

- [ ] task 1
- [ ] some new task that was added - so the old 2nd task is now the 3rd task in the section
- [ ] task 2 - I am the task that will be completed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you read my comment here: #1663 (comment)?

it contains the answer to the purpose of task.identitcalTo

I could elaborate more if needed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I did see that. I should have said that I don’t understand why the rendering of the task matters.

The line being overwritten should be identical to the original text read in to the task being edited.

If the two markdown lines differ in any way, including order of fields, something has gone wrong as the file has been edited in some way behind Tasks’ back, and I do not feel it is safe to overwrite the line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Yes, in that case .originalMarkdown is the way to go. I was being lenient with my change and allowing even for the order of the fields to change. I think a factor at play was that I sort of forgot that we had .originalMarkdown 😅

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @BluBloos Thank you, and I totally understand... I'll change it to use .originalMarkdown when I tweak the error message...

fallbackDate: dateFromFileName.value,
});
if (taskFromLine?.identicalTo(originalTask) === true) {
listItem = listItemCache;
} else {
console.error(
`Tasks: Unable to find task in file ${originalTask.path}.\n` +
`Expected task: ${originalTask.toFileLineString()}. Found task line: ${line}.`,
);
return;
}
claremacrae marked this conversation as resolved.
Show resolved Hide resolved
break;
}

Expand Down