Skip to content
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions src/algorithms/base/isrs-algorithm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { INoteEaseList } from "src/note-ease-list";

export enum Algorithm {
SM_2_OSR = "SM-2-OSR",
CUSTOM_INTERVALS = "Custom-Intervals",
}

export interface ISrsAlgorithm {
Expand Down
101 changes: 101 additions & 0 deletions src/algorithms/custom/srs-algorithm-custom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { ISrsAlgorithm } from "src/algorithms/base/isrs-algorithm";
import { RepItemScheduleInfo } from "src/algorithms/base/rep-item-schedule-info";
import { ReviewResponse } from "src/algorithms/base/repetition-item";
import { OsrNoteGraph } from "src/algorithms/osr/osr-note-graph";
import { RepItemScheduleInfoOsr } from "src/algorithms/osr/rep-item-schedule-info-osr";
// TICKS_PER_DAY not needed for custom intervals
// import { TICKS_PER_DAY } from "src/constants";
import { DueDateHistogram } from "src/due-date-histogram";
import { Note } from "src/note";
import { INoteEaseList } from "src/note-ease-list";
import { SRSettings } from "src/settings";
import { globalDateProvider } from "src/utils/dates";

export class SrsAlgorithmCustom implements ISrsAlgorithm {
private settings: SRSettings;

constructor(settings: SRSettings) {
this.settings = settings;
}

noteOnLoadedNote(_path: string, _note: Note, _noteEase: number): void {
// For custom intervals, we don't need to track note ease like SM-2
// This is a no-op for the custom intervals algorithm
}

noteCalcNewSchedule(
notePath: string,
osrNoteGraph: OsrNoteGraph,
response: ReviewResponse,
_dueDateNoteHistogram: DueDateHistogram,
): RepItemScheduleInfo {
const interval = this.getCustomInterval(response);
const dueDate = globalDateProvider.today.add(interval, "d");

return new RepItemScheduleInfoOsr(dueDate, interval, 250); // Use default ease for custom intervals
}

noteCalcUpdatedSchedule(
notePath: string,
noteSchedule: RepItemScheduleInfo,
response: ReviewResponse,
_dueDateNoteHistogram: DueDateHistogram,
): RepItemScheduleInfo {
const interval = this.getCustomInterval(response);
const dueDate = globalDateProvider.today.add(interval, "d");

return new RepItemScheduleInfoOsr(dueDate, interval, 250); // Use default ease for custom intervals
}

noteStats(): INoteEaseList {
// Return empty note stats for custom intervals
return {
dict: {},
hasEaseForPath: () => false,
getEaseByPath: () => 250,
baseEase: () => 250,
};
}

cardGetResetSchedule(): RepItemScheduleInfo {
// Reset to new card state
return null;
}

cardGetNewSchedule(
response: ReviewResponse,
_notePath: string,
_dueDateFlashcardHistogram: DueDateHistogram,
): RepItemScheduleInfo {
const interval = this.getCustomInterval(response);
const dueDate = globalDateProvider.today.add(interval, "d");

return new RepItemScheduleInfoOsr(dueDate, interval, 250); // Use default ease for custom intervals
}

cardCalcUpdatedSchedule(
response: ReviewResponse,
_schedule: RepItemScheduleInfo,
_dueDateFlashcardHistogram: DueDateHistogram,
): RepItemScheduleInfo {
const interval = this.getCustomInterval(response);
const dueDate = globalDateProvider.today.add(interval, "d");

return new RepItemScheduleInfoOsr(dueDate, interval, 250); // Use default ease for custom intervals
}

private getCustomInterval(response: ReviewResponse): number {
switch (response) {
case ReviewResponse.Easy:
return this.settings.customIntervalEasy;
case ReviewResponse.Good:
return this.settings.customIntervalGood;
case ReviewResponse.Hard:
return this.settings.customIntervalHard;
case ReviewResponse.Reset:
return 0; // Reset means new card
default:
return this.settings.customIntervalGood; // Default to Good interval
}
}
}
36 changes: 24 additions & 12 deletions src/data-store-algorithm/data-store-in-note-algorithm-osr.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Moment } from "moment";
import moment from "moment";

import { Algorithm } from "src/algorithms/base/isrs-algorithm";
import { RepItemScheduleInfo } from "src/algorithms/base/rep-item-schedule-info";
import { RepItemScheduleInfoOsr } from "src/algorithms/osr/rep-item-schedule-info-osr";
import { Card } from "src/card";
Expand Down Expand Up @@ -32,15 +33,22 @@ export class DataStoreInNoteAlgorithmOsr implements IDataStoreAlgorithm {
let result: RepItemScheduleInfo = null;
const frontmatter: Map<string, string> = await note.getFrontmatter();

if (
frontmatter &&
frontmatter.has("sr-due") &&
frontmatter.has("sr-interval") &&
frontmatter.has("sr-ease")
) {
if (frontmatter && frontmatter.has("sr-due")) {
const dueDate: Moment = moment(frontmatter.get("sr-due"), ALLOWED_DATE_FORMATS);
const interval: number = parseFloat(frontmatter.get("sr-interval"));
const ease: number = parseFloat(frontmatter.get("sr-ease"));

// For Custom Intervals, interval might not be stored, so use a default value
// The actual interval will be determined by the algorithm when scheduling
let interval: number = 1; // Default interval
if (frontmatter.has("sr-interval")) {
interval = parseFloat(frontmatter.get("sr-interval"));
}

// For Custom Intervals, ease might not be stored, so use default value
let ease: number = 250; // Default ease
if (frontmatter.has("sr-ease")) {
ease = parseFloat(frontmatter.get("sr-ease"));
}

result = new RepItemScheduleInfoOsr(dueDate, interval, ease);
}
return result;
Expand All @@ -54,13 +62,18 @@ export class DataStoreInNoteAlgorithmOsr implements IDataStoreAlgorithm {
const interval: number = schedInfo.interval;
const ease: number = schedInfo.latestEase;

// Determine what to include based on algorithm
const includeSM2Data = this.settings.algorithm === Algorithm.SM_2_OSR;
const intervalString = includeSM2Data ? `sr-interval: ${interval}\n` : "";
const easeString = includeSM2Data ? `sr-ease: ${ease}\n` : "";

// check if scheduling info exists
if (SCHEDULING_INFO_REGEX.test(fileText)) {
const schedulingInfo = SCHEDULING_INFO_REGEX.exec(fileText);
fileText = fileText.replace(
SCHEDULING_INFO_REGEX,
`---\n${schedulingInfo[1]}sr-due: ${dueString}\n` +
`sr-interval: ${interval}\nsr-ease: ${ease}\n` +
`${intervalString}${easeString}` +
`${schedulingInfo[5]}---`,
);
} else if (YAML_FRONT_MATTER_REGEX.test(fileText)) {
Expand All @@ -69,12 +82,11 @@ export class DataStoreInNoteAlgorithmOsr implements IDataStoreAlgorithm {
fileText = fileText.replace(
YAML_FRONT_MATTER_REGEX,
`---\n${existingYaml[1]}sr-due: ${dueString}\n` +
`sr-interval: ${interval}\nsr-ease: ${ease}\n---`,
`${intervalString}${easeString}---`,
);
} else {
fileText =
`---\nsr-due: ${dueString}\nsr-interval: ${interval}\n` +
`sr-ease: ${ease}\n---\n\n${fileText}`;
`---\nsr-due: ${dueString}\n` + `${intervalString}${easeString}---\n\n${fileText}`;
}

await note.write(fileText);
Expand Down
Loading
Loading