-
-
Notifications
You must be signed in to change notification settings - Fork 288
feat: Allow additional tasks states and filtering by states #675 #670
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
Changes from 27 commits
53d2d8e
bea862f
f2104c9
1bb8f9f
d8a3168
75eba71
d8a95b0
547f776
9716007
a3964f7
9c64527
f90abc4
4b88b4a
f02f2d2
67e97c6
b2ace95
3848523
788e25e
de6cb0f
010f439
bd31de1
b08bdc8
f58186a
9d27b5d
149eb34
d5976ba
292f684
69b8517
2b92499
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.js text eol=lf | ||
*.ts text eol=lf |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,10 @@ | ||
import esbuild from "esbuild"; | ||
import process from "process"; | ||
import builtins from 'builtin-modules' | ||
import esbuildSvelte from "esbuild-svelte"; | ||
import sveltePreprocess from "svelte-preprocess"; | ||
|
||
const banner = | ||
`/* | ||
import process from 'process'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file has been reformatted, which makes it impossible to see if or where the content has changed. And also, not possible to know whether any change was related to the topic of this PR, or something independent that could/should have been in a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ill reset the structure, ironically this is now formatted using the same settings as lint 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see #683 |
||
import esbuild from 'esbuild'; | ||
import builtins from 'builtin-modules'; | ||
import esbuildSvelte from 'esbuild-svelte'; | ||
import sveltePreprocess from 'svelte-preprocess'; | ||
|
||
const banner = `/* | ||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD | ||
if you want to view the source visit the plugins github repository | ||
*/ | ||
|
@@ -130,44 +129,48 @@ THE SOFTWARE. | |
*/ | ||
`; | ||
|
||
const prod = (process.argv[2] === 'production'); | ||
|
||
esbuild.build({ | ||
banner: { | ||
js: banner, | ||
}, | ||
bundle: true, | ||
entryPoints: ['main.ts'], | ||
external: [ | ||
'obsidian', | ||
'electron', | ||
'codemirror', | ||
'@codemirror/autocomplete', | ||
'@codemirror/closebrackets', | ||
'@codemirror/commands', | ||
'@codemirror/fold', | ||
'@codemirror/gutter', | ||
'@codemirror/history', | ||
'@codemirror/language', | ||
'@codemirror/rangeset', | ||
'@codemirror/rectangular-selection', | ||
'@codemirror/search', | ||
'@codemirror/state', | ||
'@codemirror/stream-parser', | ||
'@codemirror/text', | ||
'@codemirror/view', | ||
...builtins | ||
], | ||
format: 'cjs', | ||
logLevel: "info", | ||
outfile: 'main.js', | ||
plugins: [ | ||
esbuildSvelte({ | ||
preprocess: sveltePreprocess() | ||
}), | ||
], | ||
sourcemap: prod ? false : 'inline', | ||
target: 'es2016', | ||
treeShaking: true, | ||
watch: !prod, | ||
}).catch(() => process.exit(1)); | ||
const prod = process.argv[2] === 'production'; | ||
const dev = process.argv[2] === 'development'; | ||
|
||
esbuild | ||
.build({ | ||
banner: { | ||
js: banner, | ||
}, | ||
bundle: true, | ||
entryPoints: ['main.ts'], | ||
external: [ | ||
'obsidian', | ||
'electron', | ||
'codemirror', | ||
'@codemirror/autocomplete', | ||
'@codemirror/closebrackets', | ||
'@codemirror/commands', | ||
'@codemirror/fold', | ||
'@codemirror/gutter', | ||
'@codemirror/history', | ||
'@codemirror/language', | ||
'@codemirror/rangeset', | ||
'@codemirror/rectangular-selection', | ||
'@codemirror/search', | ||
'@codemirror/state', | ||
'@codemirror/stream-parser', | ||
'@codemirror/text', | ||
'@codemirror/view', | ||
...builtins, | ||
], | ||
format: 'cjs', | ||
logLevel: 'info', | ||
minify: prod ? true : false, | ||
outfile: 'main.js', | ||
plugins: [ | ||
esbuildSvelte({ | ||
preprocess: sveltePreprocess(), | ||
}), | ||
], | ||
sourcemap: prod ? false : 'inline', | ||
target: 'es2016', | ||
treeShaking: true, | ||
watch: !prod && !dev, | ||
}) | ||
.catch(() => process.exit(1)); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,9 +6,11 @@ | |
"scripts": { | ||
"dev": "node esbuild.config.mjs", | ||
"build": "node esbuild.config.mjs production", | ||
"build:dev": "node esbuild.config.mjs development", | ||
"lint": "eslint ./src --fix && eslint ./tests --fix && tsc --noEmit --pretty && svelte-check", | ||
"test": "jest --ci", | ||
"test:dev": "jest --watch" | ||
"test:dev": "jest --watch", | ||
"test:obsidian": "pwsh -ExecutionPolicy Unrestricted -NoProfile -File ./scripts/Test-TasksInLocalObsidian.ps1" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ooh, using PowerShell to drive Obsidian. This is very intriguing! Will it work on Linux and Mac? (I know that PowerShell has been released on those platforms, but I don't know whether it can drive Obsidian on those platforms. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Later: it doesn't drive obsidian, it copies a distribution in to a vault. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it works across platforms. I use it on my linux machine and in WSL on windows. I am using it as bash sends me around the twist these days with string manipulation. Being able to work with objects in the shell is much better. I am slowly playing with a PowerShell module that will work with obsidian and the shell plugin also supports running PowerShell scripts. This will setup synlinks to the vault you specify in a environment variable or via the command line and then start the build watch process. Makes the dev cycle faster. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see #683 |
||
}, | ||
"keywords": [ | ||
"obsidian", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
[CmdletBinding()] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, based on the file name, I misunderstood the purpose of this file. I though it was actually testing Obsidian, but it is copying the built plugin in to an Obsidian vault. That's still very useful, but also a candidate for being in a separate PR please (alongside the associated change to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am using it to help me work on this PR. So there will be a chicken egg scenario. Ill make a separate PR and if it goes in first then this will disappear from this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #683 |
||
param ( | ||
[Parameter(HelpMessage = 'The path to the plugins folder uner the .obsidian directory.')] | ||
[String] | ||
$ObsidianPluginRoot = $env:OBSIDIAN_PLUGIN_ROOT, | ||
[Parameter(HelpMessage = 'The folder name of the plugin to copy the files to.')] | ||
[String] | ||
$PluginFolderName = 'obsidian-tasks-plugin' | ||
) | ||
|
||
$repoRoot = (Resolve-Path -Path $(git rev-parse --show-toplevel)).Path | ||
|
||
if (-not (Test-Path $ObsidianPluginRoot)) { | ||
Write-Error "Obsidian plugin root not found: $ObsidianPluginRoot" | ||
return | ||
} else { | ||
Write-Host "Obsidian plugin root found: $ObsidianPluginRoot" | ||
} | ||
|
||
Push-Location $repoRoot | ||
Write-Host "Repo root: $repoRoot" | ||
|
||
yarn run build:dev | ||
|
||
if ($?) { | ||
Write-Output 'Build successful' | ||
|
||
$filesToLink = @('main.js', 'styles.css', 'manifest.json') | ||
|
||
foreach ($file in $filesToLink ) { | ||
if ((Get-Item "$ObsidianPluginRoot/$PluginFolderName/$file" ).LinkType -ne 'SymbolicLink') { | ||
Write-Output "Removing $file from plugin folder and linking" | ||
Remove-Item "$ObsidianPluginRoot/$PluginFolderName/$file" -Force | ||
New-Item -ItemType SymbolicLink -Path "$ObsidianPluginRoot/$PluginFolderName/$file" -Target "$repoRoot/$file" | ||
} else { | ||
(Get-Item "$ObsidianPluginRoot/$PluginFolderName/$file" ).LinkType | ||
} | ||
} | ||
|
||
$hasHotReload = Test-Path "$ObsidianPluginRoot/$PluginFolderName/.hotreload" | ||
|
||
if (!$hasHotReload) { | ||
Write-Output 'Creating hotreload file' | ||
'' | Set-Content "$ObsidianPluginRoot/$PluginFolderName/.hotreload" | ||
} | ||
|
||
yarn run dev | ||
|
||
} else { | ||
Write-Error 'Build failed' | ||
} | ||
|
||
Pop-Location |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
import { App, Editor, MarkdownView, View } from 'obsidian'; | ||
import { StatusRegistry } from 'StatusRegistry'; | ||
import { TaskModal } from '../TaskModal'; | ||
import { Priority, Status, Task } from '../Task'; | ||
import { Status } from '../Status'; | ||
import { Priority, Task } from '../Task'; | ||
|
||
export const createOrEdit = ( | ||
checking: boolean, | ||
|
@@ -64,11 +66,10 @@ const taskFromLine = ({ line, path }: { line: string; path: string }): Task => { | |
// Should never happen; everything in the regex is optional. | ||
console.error('Tasks: Cannot create task on line:', line); | ||
return new Task({ | ||
status: Status.Todo, | ||
status: Status.TODO, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For my own education, I'm curious as to why Asking as it increases the number of changes to review, not because I want to change it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consistency in code, as these are constants I have seen they should be upper case in TS/JS. Also makes it super easy to see when reading code that these are not a normal variable. |
||
description: '', | ||
path, | ||
indentation: '', | ||
originalStatusCharacter: ' ', | ||
priority: Priority.None, | ||
startDate: null, | ||
scheduledDate: null, | ||
|
@@ -86,7 +87,7 @@ const taskFromLine = ({ line, path }: { line: string; path: string }): Task => { | |
|
||
const indentation: string = nonTaskMatch[1]; | ||
const statusString: string = nonTaskMatch[3] ?? ' '; | ||
const status = statusString === ' ' ? Status.Todo : Status.Done; | ||
const status = StatusRegistry.getInstance().byIndicator(statusString); | ||
let description: string = nonTaskMatch[4]; | ||
|
||
const blockLinkMatch = line.match(Task.blockLinkRegex); | ||
|
@@ -101,7 +102,6 @@ const taskFromLine = ({ line, path }: { line: string; path: string }): Task => { | |
description, | ||
path, | ||
indentation, | ||
originalStatusCharacter: statusString, | ||
blockLink, | ||
priority: Priority.None, | ||
startDate: null, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// import { Editor, MarkdownView, View } from 'obsidian'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see elsewhere that you've introduced a Feature Toggle, and I do like that idea. I agree that it allows working code to be committed to main, to enable testing before it's ready for prime-time. https://martinfowler.com/articles/feature-toggles.html Sorry if this comment is premature (I did check that the PR is ready for review) but the usual behaviour of feature toggles is to allow experimental code to be turned on or off by changing the toggle. As it's all commented out, I'm unsure how we can test it. Would it be possible for all the UI code to be uncommented out, and then for the code at run-time to only enable the new features if the feature toggle is turned on? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Later: I see that the feature toggle is about whether to show a pop-up menu, and this code is about adding a command. I still would suggest the new code be activated, even if it's not called, so that if there are any future refactorings, like renaming symbols, IDEs would update the inactivated code too, preventing the commented-out code later needing to be manually updated for any changes made in between. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Coming in a separate PR. I added the feature capability in late in the cycle so it is skipped for the status change as the refactor is to large. However the UI will be behind the switch as it may be more problematic. All the UI code is just txt files for the moments as I think it through. This means that this PR can go in and the next one will enable that behind the feature flag. When a feature is marked as stable we can have the settings automatically show it in the main body as well with a warning if the user has it disabled stating that it is now stable and available for use. |
||
|
||
// import { Task } from '../Task'; | ||
|
||
// import { promptForMark } from '../ui/TaskMarkModal'; | ||
// export const selectStatus = (checking: boolean, editor: Editor, view: View) => { | ||
// const mark = await promptForMark(this.app, this.plugin); | ||
// if (mark) { | ||
// this.markTaskOnLines(mark, this.getCurrentLinesFromEditor(editor)); | ||
// } | ||
|
||
// if (checking) { | ||
// if (!(view instanceof MarkdownView)) { | ||
// // If we are not in a markdown view, the command shouldn't be shown. | ||
// return false; | ||
// } | ||
|
||
// // The command should always trigger in a markdown view: | ||
// // - Convert lines to list items. | ||
// // - Convert list items to tasks. | ||
// // - Toggle tasks' status. | ||
// return true; | ||
// } | ||
|
||
// if (!(view instanceof MarkdownView)) { | ||
// // Should never happen due to check above. | ||
// return; | ||
// } | ||
|
||
// // We are certain we are in the editor due to the check above. | ||
// const path = view.file?.path; | ||
// if (path === undefined) { | ||
// return; | ||
// } | ||
|
||
// const cursorPosition = editor.getCursor(); | ||
// const lineNumber = cursorPosition.line; | ||
// const line = editor.getLine(lineNumber); | ||
|
||
// const toggledLine = toggleLine({ line, path }); | ||
// editor.setLine(lineNumber, toggledLine); | ||
|
||
// // The cursor is moved to the end of the line by default. | ||
// // If there is text on the line, put the cursor back where it was on the line. | ||
// if (/[^ [\]*-]/.test(toggledLine)) { | ||
// editor.setCursor({ | ||
// line: cursorPosition.line, | ||
// // Need to move the cursor by the distance we added to the beginning. | ||
// ch: cursorPosition.ch + toggledLine.length - line.length, | ||
// }); | ||
// } | ||
// }; | ||
|
||
// const toggleLine = ({ line, path }: { line: string; path: string }): string => { | ||
// let toggledLine: string = line; | ||
|
||
// 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. | ||
// }); | ||
// if (task !== null) { | ||
// toggledLine = toggleTask({ task }); | ||
// } else { | ||
// // If the task is null this means that we have one of: | ||
// // 1. a regular checklist item | ||
// // 2. a list item | ||
// // 3. a simple text line | ||
|
||
// // The task regex will match checklist items. | ||
// const regexMatch = line.match(Task.taskRegex); | ||
// if (regexMatch !== null) { | ||
// toggledLine = toggleChecklistItem({ regexMatch }); | ||
// } else { | ||
// // This is not a checklist item. It is one of: | ||
// // 1. a list item | ||
// // 2. a simple text line | ||
|
||
// const listItemRegex = /^([\s\t]*)([-*])/; | ||
// if (listItemRegex.test(line)) { | ||
// // Let's convert the list item to a checklist item. | ||
// toggledLine = line.replace(listItemRegex, '$1$2 [ ]'); | ||
// } else { | ||
// // Let's convert the line to a list item. | ||
// toggledLine = line.replace(/^([\s\t]*)/, '$1- '); | ||
// } | ||
// } | ||
// } | ||
|
||
// return toggledLine; | ||
// }; | ||
|
||
// const toggleTask = ({ task }: { task: Task }): string => { | ||
// // Toggle a regular task. | ||
// const toggledTasks = task.toggle(); | ||
// const serialized = toggledTasks | ||
// .map((task: Task) => task.toFileLineString()) | ||
// .join('\n'); | ||
|
||
// return serialized; | ||
// }; | ||
|
||
// const toggleChecklistItem = ({ | ||
// regexMatch, | ||
// }: { | ||
// regexMatch: RegExpMatchArray; | ||
// }): string => { | ||
// // It's a checklist item, let's toggle it. | ||
// const indentation = regexMatch[1]; | ||
// const statusString = regexMatch[2].toLowerCase(); | ||
// const body = regexMatch[3]; | ||
|
||
// const toggledStatusString = statusString === ' ' ? 'x' : ' '; | ||
|
||
// const toggledLine = `${indentation}- [${toggledStatusString}] ${body}`; | ||
|
||
// return toggledLine; | ||
// }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import type { App, Editor, Plugin, View } from 'obsidian'; | ||
|
||
import { createOrEdit } from './CreateOrEdit'; | ||
//import { selectStatus } from './SelectStatus'; | ||
|
||
import { toggleDone } from './ToggleDone'; | ||
|
||
|
@@ -32,5 +34,12 @@ export class Commands { | |
icon: 'check-in-circle', | ||
editorCheckCallback: toggleDone, | ||
}); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this check be activated if the feature toggle is on? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, the feature toggle is specific to the pop-up menu. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, I removed it out to get a clean build and this PR in and will either add to this PR or will be in one to follow and under the flag. I have another draft PR in place using the feature flags based on this PR. |
||
// plugin.addCommand({ | ||
// id: 'select-status-modal', | ||
// name: 'Select Status', | ||
// icon: 'check-in-circle', | ||
// editorCheckCallback: selectStatus, | ||
// }); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does changing line endings relate to "feat: Allow additional tasks states and filtering by states"?
Could this be a separate PR, with a statement about motivation?
What impact will this have on anyone who already has a clone of this repo on Windows? In the past, when these attributes have changed, I think I have struggled to get a clean repo, because it sees any local CRLF as differences. I seem to recall being confused, in any case.
From my own experience, I feel that mixing (seemingly) unrelated changes inside one PR generally makes it harder for reviews. The more focussed a PR is, the quicker it can be reviewed, and the quicker separate PRs for later features can be started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reduces noise in windows, if you have CRLF and then add them in the file will just go away as git is smart enough to know that they are the same on commit/push. However in a IDE they will be different as CRLF <> LF and you will get reg conflicts.
Adding this in just lets the IDE/git know they should always be LF on all operating systems and to ignore the git config settings for LF/CRLF for these files.
I can add this to a very small PR if needed, typically we would not make a separate PR for something like this and place it in a change going in as it is small and easily identified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made #682, so when it goes in an I merge with main this file will go away from this PR.