Skip to content

Commit

Permalink
Merge pull request #10 from joeriddles/9/exclude-finished-tasks
Browse files Browse the repository at this point in the history
Exclude finished tasks by default
  • Loading branch information
joeriddles authored Feb 27, 2024
2 parents 43d31a2 + cb3d399 commit da788d7
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 48 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
"source.fixAll": "explicit"
},
},
"eslint.codeActionsOnSave.mode": "problems"
"eslint.codeActionsOnSave.mode": "problems",
"cSpell.words": [
"todos"
]
}
95 changes: 60 additions & 35 deletions findTodos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,82 @@
* TypeScript mirror of https://github.com/joeriddles/notes
*/

import { TFile } from "obsidian"
import { TFile } from "obsidian";
import { ExtendedTaskListsSettings } from 'settings';

enum TaskType {
NotStarted = " ",
InProgress = ".",
WontDo = "~",
Done = "x",
}

interface Todo {
task: string
task: TaskType
text: string
file: TFile
}

const TODO_PATTERN = /^\s*-\s?\[(?<task>.)\]\s+(?<text>.*)$/

function parseTodos(file: TFile, contents: string): Todo[] {
const lines = contents.split(/[\r\n]+/)
const matches = lines
.map(line => line.match(TODO_PATTERN))
.filter(match => match != null) as RegExpMatchArray[]
const todos = matches.map(match => {
const task = match.groups?.task
const text = match.groups?.text
return { task, text, file } as Todo
})
return todos
}
class TodoService {
settings: ExtendedTaskListsSettings

async function saveTodos(file: TFile, todos: Todo[]): Promise<void> {
let data = ""
constructor(settings: ExtendedTaskListsSettings) {
this.settings = settings
}

parseTodos(file: TFile, contents: string): Todo[] {
const lines = contents.split(/[\r\n]+/)
const matches = lines
.map(line => line.match(TODO_PATTERN))
.filter(match => match != null) as RegExpMatchArray[]
const todos = matches.map(match => {
const task = match.groups?.task
const text = match.groups?.text
return { task, text, file } as Todo
})
return todos
}

// Sort oldest-to-newest
todos.sort((a, b) => a.file.stat.mtime - b.file.stat.mtime)
async saveTodos(file: TFile, todos: Todo[]): Promise<void> {
let data = ""

// Group by file
const todosByFile: Map<TFile, Todo[]> = new Map();
todos.forEach(todo => {
if (!todosByFile.get(todo.file)) {
todosByFile.set(todo.file, [])
}
// Sort oldest-to-newest
todos.sort((a, b) => a.file.stat.mtime - b.file.stat.mtime)

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
todosByFile.get(todo.file)!.push(todo)
})
// Exclude finished tasks
todos = todos.filter(todo =>
(todo.task === TaskType.NotStarted && this.settings.includeNotStarted)
|| (todo.task === TaskType.InProgress && this.settings.includeInProgress)
|| (todo.task === TaskType.WontDo && this.settings.includeWontDo)
|| (todo.task === TaskType.Done && this.settings.includeDone)
)

todosByFile.forEach((todos, file) => {
const urlEncodedFilePath = encodeURI(file.path)
data += `- [${file.basename}](${urlEncodedFilePath})\n`
// Group by file
const todosByFile: Map<TFile, Todo[]> = new Map();
todos.forEach(todo => {
data += ` - [${todo.task}] ${todo.text}\n`
if (!todosByFile.get(todo.file)) {
todosByFile.set(todo.file, [])
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
todosByFile.get(todo.file)!.push(todo)
})

todosByFile.forEach((todos, file) => {
const urlEncodedFilePath = encodeURI(file.path)
data += `- [${file.basename}](${urlEncodedFilePath})\n`
todos.forEach(todo => {
data += ` - [${todo.task}] ${todo.text}\n`
})
})
})

file.vault.modify(file, data)
file.vault.modify(file, data)
}
}

export { parseTodos, saveTodos }
export type { Todo }

export default TodoService
export type { Todo };

56 changes: 44 additions & 12 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { App, Plugin, PluginSettingTab, Setting, TFile, Vault } from 'obsidian'
import { Todo, parseTodos, saveTodos } from './findTodos'

interface ExtendedTaskListsSettings {
todoFilename: string
}

const DEFAULT_SETTINGS: ExtendedTaskListsSettings = {
todoFilename: "TODO.md"
}
import { App, Plugin, PluginSettingTab, Setting, TFile, Vault } from 'obsidian';
import { DEFAULT_SETTINGS, ExtendedTaskListsSettings } from 'settings';
import TodoService, { Todo } from './findTodos';

export default class ExtendedTaskListsPlugin extends Plugin {
settings: ExtendedTaskListsSettings
Expand Down Expand Up @@ -84,15 +77,17 @@ export default class ExtendedTaskListsPlugin extends Plugin {
updateTodo = async () => {
const vault = this.app.vault

const service = new TodoService(this.settings)

const markdownFiles = vault.getMarkdownFiles().filter(file => file.name != this.settings.todoFilename)
const todos: Todo[] = []
markdownFiles.forEach(async (file) => {
const contents = await vault.cachedRead(file)
todos.push(...parseTodos(file, contents))
todos.push(...service.parseTodos(file, contents))
})

const todoFile = await this.getOrCreateTodoFile(vault);
await saveTodos(todoFile, todos)
await service.saveTodos(todoFile, todos)
}

getOrCreateTodoFile = async (vault: Vault): Promise<TFile> => {
Expand Down Expand Up @@ -124,6 +119,7 @@ class ExtendedTaskListsSettingTab extends PluginSettingTab {
const { containerEl } = this

containerEl.empty()
this.containerEl.createEl("h2", { text: "Generated TODO" });

new Setting(containerEl)
.setName('TODO filename')
Expand All @@ -133,5 +129,41 @@ class ExtendedTaskListsSettingTab extends PluginSettingTab {
this.plugin.settings.todoFilename = value
await this.plugin.saveSettings()
}))

new Setting(containerEl)
.setName('Include not started tasks')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.includeNotStarted)
.onChange(async (value) => {
this.plugin.settings.includeNotStarted = value
await this.plugin.saveSettings()
}))

new Setting(containerEl)
.setName('Include in progress tasks')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.includeInProgress)
.onChange(async (value) => {
this.plugin.settings.includeInProgress = value
await this.plugin.saveSettings()
}))

new Setting(containerEl)
.setName('Include won\'t do tasks')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.includeWontDo)
.onChange(async (value) => {
this.plugin.settings.includeWontDo = value
await this.plugin.saveSettings()
}))

new Setting(containerEl)
.setName('Include done tasks')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.includeDone)
.onChange(async (value) => {
this.plugin.settings.includeDone = value
await this.plugin.saveSettings()
}))
}
}
19 changes: 19 additions & 0 deletions settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
interface ExtendedTaskListsSettings {
todoFilename: string;
includeNotStarted: boolean;
includeInProgress: boolean;
includeWontDo: boolean;
includeDone: boolean;
}

const DEFAULT_SETTINGS: ExtendedTaskListsSettings = {
todoFilename: "TODO.md",
includeNotStarted: true,
includeInProgress: true,
includeWontDo: false,
includeDone: false,
}

export { DEFAULT_SETTINGS };
export type { ExtendedTaskListsSettings };

0 comments on commit da788d7

Please sign in to comment.