Skip to content
Merged
15 changes: 14 additions & 1 deletion src/Query/Filter/PriorityField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export class PriorityField extends Field {
// is to capture them in Nested Capture Groups, like this:
// (leading-white-space-in-outer-capture-group(values-to-use-are-in-inner-capture-group))
// The capture groups are numbered in the order of their opening brackets, from left to right.
private static readonly priorityRegexp = /^priority(\s+is)?(\s+(above|below|not))?(\s+(low|none|medium|high))$/;
private static readonly priorityRegexp =
/^priority(\s+is)?(\s+(above|below|not))?(\s+(lowest|low|none|medium|high|highest))$/;

createFilterOrErrorMessage(line: string): FilterOrErrorMessage {
const result = new FilterOrErrorMessage(line);
Expand All @@ -20,6 +21,9 @@ export class PriorityField extends Field {
let filterPriority: Priority | null = null;

switch (filterPriorityString) {
case 'lowest':
filterPriority = Priority.Lowest;
break;
case 'low':
filterPriority = Priority.Low;
break;
Expand All @@ -32,6 +36,9 @@ export class PriorityField extends Field {
case 'high':
filterPriority = Priority.High;
break;
case 'highest':
filterPriority = Priority.Highest;
break;
}

if (filterPriority === null) {
Expand Down Expand Up @@ -92,6 +99,9 @@ export class PriorityField extends Field {
case Priority.High:
priorityName = 'High';
break;
case Priority.Highest:
priorityName = 'Highest';
break;
case Priority.Medium:
priorityName = 'Medium';
break;
Expand All @@ -101,6 +111,9 @@ export class PriorityField extends Field {
case Priority.Low:
priorityName = 'Low';
break;
case Priority.Lowest:
priorityName = 'Lowest';
break;
}
return [`Priority ${task.priority}: ${priorityName}`];
};
Expand Down
8 changes: 8 additions & 0 deletions src/Suggestor/Suggestor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ function addTaskPropertySuggestions(
appendText: `${symbols.scheduledDateSymbol} `,
});
if (!hasPriority(line)) {
genericSuggestions.push({
displayText: `${symbols.prioritySymbols.Highest} highest priority`,
appendText: `${symbols.prioritySymbols.Highest} `,
});
genericSuggestions.push({
displayText: `${symbols.prioritySymbols.High} high priority`,
appendText: `${symbols.prioritySymbols.High} `,
Expand All @@ -95,6 +99,10 @@ function addTaskPropertySuggestions(
displayText: `${symbols.prioritySymbols.Low} low priority`,
appendText: `${symbols.prioritySymbols.Low} `,
});
genericSuggestions.push({
displayText: `${symbols.prioritySymbols.Lowest} lowest priority`,
appendText: `${symbols.prioritySymbols.Lowest} `,
});
}
if (!line.includes(symbols.recurrenceSymbol))
genericSuggestions.push({
Expand Down
10 changes: 6 additions & 4 deletions src/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import { compareByDate } from './lib/DateTools';
* @enum {number}
*/
export enum Priority {
High = '1',
Medium = '2',
None = '3',
Low = '4',
Highest = '1',
High = '2',
Medium = '3',
None = '4',
Low = '5',
Lowest = '6',
}

export class TaskRegularExpressions {
Expand Down
4 changes: 3 additions & 1 deletion src/TaskLineRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,11 @@ function getComponentClassesAndData(component: TaskLayoutComponent, task: Task):
break;
case 'priority': {
let priorityValue = null;
if (task.priority === taskModule.Priority.High) priorityValue = 'high';
if (task.priority === taskModule.Priority.Highest) priorityValue = 'highest';
else if (task.priority === taskModule.Priority.High) priorityValue = 'high';
else if (task.priority === taskModule.Priority.Medium) priorityValue = 'medium';
else if (task.priority === taskModule.Priority.Low) priorityValue = 'low';
else if (task.priority === taskModule.Priority.Lowest) priorityValue = 'lowest';
else priorityValue = 'normal';
dataAttributes['taskPriority'] = priorityValue;
genericClasses.push(LayoutClasses.priority);
Expand Down
8 changes: 7 additions & 1 deletion src/TaskSerializer/DataviewTaskSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ function toInlineFieldRegex(innerFieldRegex: RegExp): RegExp {
*/
export const DATAVIEW_SYMBOLS = {
prioritySymbols: {
Highest: 'priority:: highest',
High: 'priority:: high',
Medium: 'priority:: medium',
Low: 'priority:: low',
Lowest: 'priority:: lowest',
None: '',
},
startDateSymbol: 'start::',
Expand All @@ -72,7 +74,7 @@ export const DATAVIEW_SYMBOLS = {
doneDateSymbol: 'completion::',
recurrenceSymbol: 'repeat::',
TaskFormatRegularExpressions: {
priorityRegex: toInlineFieldRegex(/priority:: *(high|medium|low)/),
priorityRegex: toInlineFieldRegex(/priority:: *(highest|high|medium|low|lowest)/),
startDateRegex: toInlineFieldRegex(/start:: *(\d{4}-\d{2}-\d{2})/),
createdDateRegex: toInlineFieldRegex(/created:: *(\d{4}-\d{2}-\d{2})/),
scheduledDateRegex: toInlineFieldRegex(/scheduled:: *(\d{4}-\d{2}-\d{2})/),
Expand All @@ -93,12 +95,16 @@ export class DataviewTaskSerializer extends DefaultTaskSerializer {

protected parsePriority(p: string): Priority {
switch (p) {
case 'highest':
return Priority.Highest;
case 'high':
return Priority.High;
case 'medium':
return Priority.Medium;
case 'low':
return Priority.Low;
case 'lowest':
return Priority.Lowest;
default:
return Priority.None;
}
Expand Down
16 changes: 14 additions & 2 deletions src/TaskSerializer/DefaultTaskSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import type { TaskDetails, TaskSerializer } from '.';
*/
export interface DefaultTaskSerializerSymbols {
readonly prioritySymbols: {
Highest: string;
High: string;
Medium: string;
Low: string;
Lowest: string;
None: string;
};
readonly startDateSymbol: string;
Expand All @@ -41,9 +43,11 @@ export interface DefaultTaskSerializerSymbols {
*/
export const DEFAULT_SYMBOLS: DefaultTaskSerializerSymbols = {
prioritySymbols: {
Highest: '🔝',
High: '⏫',
Medium: '🔼',
Low: '🔽',
Lowest: '⏬',
None: '',
},
startDateSymbol: '🛫',
Expand All @@ -55,7 +59,7 @@ export const DEFAULT_SYMBOLS: DefaultTaskSerializerSymbols = {
TaskFormatRegularExpressions: {
// The following regex's end with `$` because they will be matched and
// removed from the end until none are left.
priorityRegex: /([⏫🔼🔽])$/u,
priorityRegex: /([🔝⏫🔼🔽])$/u,
startDateRegex: /🛫 *(\d{4}-\d{2}-\d{2})$/u,
createdDateRegex: /➕ *(\d{4}-\d{2}-\d{2})$/u,
scheduledDateRegex: /[⏳⌛] *(\d{4}-\d{2}-\d{2})$/u,
Expand Down Expand Up @@ -103,12 +107,16 @@ export class DefaultTaskSerializer implements TaskSerializer {
case 'priority': {
let priority: string = '';

if (task.priority === Priority.High) {
if (task.priority === Priority.Highest) {
priority = ' ' + prioritySymbols.Highest;
} else if (task.priority === Priority.High) {
priority = ' ' + prioritySymbols.High;
} else if (task.priority === Priority.Medium) {
priority = ' ' + prioritySymbols.Medium;
} else if (task.priority === Priority.Low) {
priority = ' ' + prioritySymbols.Low;
} else if (task.priority === Priority.Lowest) {
priority = ' ' + prioritySymbols.Lowest;
}
return priority;
}
Expand Down Expand Up @@ -160,12 +168,16 @@ export class DefaultTaskSerializer implements TaskSerializer {
protected parsePriority(p: string): Priority {
const { prioritySymbols } = this.symbols;
switch (p) {
case prioritySymbols.Lowest:
return Priority.Lowest;
case prioritySymbols.Low:
return Priority.Low;
case prioritySymbols.Medium:
return Priority.Medium;
case prioritySymbols.High:
return Priority.High;
case prioritySymbols.Highest:
return Priority.Highest;
default:
return Priority.None;
}
Expand Down
14 changes: 11 additions & 3 deletions src/Urgency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,26 @@ export class Urgency {
}

switch (task.priority) {
// High
// Highest
case '1':
urgency += 1.5 * Urgency.priorityCoefficient;
break;
// High
case '2':
urgency += 1.0 * Urgency.priorityCoefficient;
break;
// Medium
case '2':
case '3':
urgency += 0.65 * Urgency.priorityCoefficient;
break;
// None
case '3':
case '4':
urgency += 0.325 * Urgency.priorityCoefficient;
break;
// Low
case '5':
urgency += 0.1 * Urgency.priorityCoefficient;
break;
}

return urgency;
Expand Down
47 changes: 43 additions & 4 deletions tests/Query/Filter/PriorityField.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,59 +17,92 @@ function testTaskFilterForTaskWithPriority(filter: string, priority: Priority, e
}

describe('priority is', () => {
it('priority is highest', () => {
const filter = 'priority is highest';
testTaskFilterForTaskWithPriority(filter, Priority.Highest, true);
testTaskFilterForTaskWithPriority(filter, Priority.High, false);
testTaskFilterForTaskWithPriority(filter, Priority.Medium, false);
testTaskFilterForTaskWithPriority(filter, Priority.None, false);
testTaskFilterForTaskWithPriority(filter, Priority.Low, false);
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, false);
});

it('priority is high', () => {
const filter = 'priority is high';
testTaskFilterForTaskWithPriority(filter, Priority.Highest, false);
testTaskFilterForTaskWithPriority(filter, Priority.High, true);
testTaskFilterForTaskWithPriority(filter, Priority.Medium, false);
testTaskFilterForTaskWithPriority(filter, Priority.None, false);
testTaskFilterForTaskWithPriority(filter, Priority.Low, false);
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, false);
});

it('priority is medium', () => {
const filter = 'priority is medium';
testTaskFilterForTaskWithPriority(filter, Priority.Highest, false);
testTaskFilterForTaskWithPriority(filter, Priority.High, false);
testTaskFilterForTaskWithPriority(filter, Priority.Medium, true);
testTaskFilterForTaskWithPriority(filter, Priority.None, false);
testTaskFilterForTaskWithPriority(filter, Priority.Low, false);
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, false);
});

it('priority is none', () => {
const filter = 'priority is none';
testTaskFilterForTaskWithPriority(filter, Priority.Highest, false);
testTaskFilterForTaskWithPriority(filter, Priority.High, false);
testTaskFilterForTaskWithPriority(filter, Priority.Medium, false);
testTaskFilterForTaskWithPriority(filter, Priority.None, true);
testTaskFilterForTaskWithPriority(filter, Priority.Low, false);
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, false);
});

it('priority is low', () => {
const filter = 'priority is low';
testTaskFilterForTaskWithPriority(filter, Priority.Highest, false);
testTaskFilterForTaskWithPriority(filter, Priority.High, false);
testTaskFilterForTaskWithPriority(filter, Priority.Medium, false);
testTaskFilterForTaskWithPriority(filter, Priority.None, false);
testTaskFilterForTaskWithPriority(filter, Priority.Low, true);
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, false);
});

it('priority is lowest', () => {
const filter = 'priority is lowest';
testTaskFilterForTaskWithPriority(filter, Priority.Highest, false);
testTaskFilterForTaskWithPriority(filter, Priority.High, false);
testTaskFilterForTaskWithPriority(filter, Priority.Medium, false);
testTaskFilterForTaskWithPriority(filter, Priority.None, false);
testTaskFilterForTaskWithPriority(filter, Priority.Low, false);
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, true);
});
});

describe('priority above', () => {
it('priority above none', () => {
const filter = 'priority above none';
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, false);
testTaskFilterForTaskWithPriority(filter, Priority.Low, false);
testTaskFilterForTaskWithPriority(filter, Priority.None, false);
testTaskFilterForTaskWithPriority(filter, Priority.Medium, true);
testTaskFilterForTaskWithPriority(filter, Priority.High, true);
testTaskFilterForTaskWithPriority(filter, Priority.Highest, true);
});
});

describe('priority below', () => {
it('priority below none', () => {
const filter = 'priority below none';
testTaskFilterForTaskWithPriority(filter, Priority.Lowest, true);
testTaskFilterForTaskWithPriority(filter, Priority.Low, true);
testTaskFilterForTaskWithPriority(filter, Priority.None, false);
});
});

describe('priority is not', () => {
it.each([
['lowest', Priority.Lowest, false],
['lowest', Priority.Low, true],
['low', Priority.Low, false],
['low', Priority.None, true],
['none', Priority.None, false],
Expand All @@ -78,6 +111,8 @@ describe('priority is not', () => {
['medium', Priority.Medium, false],
['high', Priority.Medium, true],
['high', Priority.High, false],
['highest', Priority.Highest, false],
['highest', Priority.High, true],
])('priority is not %s (with %s)', (filter: string, input: Priority, expected: boolean) => {
// TODO Use name of input priority instead of
testTaskFilterForTaskWithPriority(`priority is not ${filter}`, input, expected);
Expand Down Expand Up @@ -142,9 +177,11 @@ describe('sorting by priority', () => {
// Assert
// This tests each adjacent pair of priority values, in descending order,
// to prove that sorting of all combinations will be correct.
expectTaskComparesBefore(sorter, with_priority(Priority.Highest), with_priority(Priority.High));
expectTaskComparesBefore(sorter, with_priority(Priority.High), with_priority(Priority.Medium));
expectTaskComparesBefore(sorter, with_priority(Priority.Medium), with_priority(Priority.None));
expectTaskComparesBefore(sorter, with_priority(Priority.None), with_priority(Priority.Low));
expectTaskComparesBefore(sorter, with_priority(Priority.Low), with_priority(Priority.Lowest));

expectTaskComparesEqual(sorter, with_priority(Priority.None), with_priority(Priority.None));
});
Expand All @@ -163,10 +200,12 @@ describe('grouping by priority', () => {
});

it.each([
['- [ ] a ⏫', ['Priority 1: High']],
['- [ ] a 🔼', ['Priority 2: Medium']],
['- [ ] a', ['Priority 3: None']],
['- [ ] a 🔽', ['Priority 4: Low']],
['- [ ] a 🔝', ['Priority 1: Highest']],
['- [ ] a ⏫', ['Priority 2: High']],
['- [ ] a 🔼', ['Priority 3: Medium']],
['- [ ] a', ['Priority 4: None']],
['- [ ] a 🔽', ['Priority 5: Low']],
['- [ ] a ⏬', ['Priority 6: Lowest']],
])('task "%s" should have groups: %s', (taskLine: string, groups: string[]) => {
// Arrange
const grouper = new PriorityField().createGrouper().grouper;
Expand Down
Loading