@beauraines/rtm-cli 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FUNDING.yml +12 -0
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/build.js +86 -0
- package/config.json +40 -0
- package/package.json +58 -0
- package/screens/ls.png +0 -0
- package/screens/lsd.png +0 -0
- package/screens/lsp.png +0 -0
- package/screens/planner.png +0 -0
- package/src/cli.js +434 -0
- package/src/cmd/add.js +100 -0
- package/src/cmd/addList.js +92 -0
- package/src/cmd/addTags.js +85 -0
- package/src/cmd/archiveList.js +78 -0
- package/src/cmd/comp.js +82 -0
- package/src/cmd/decPri.js +82 -0
- package/src/cmd/due.js +82 -0
- package/src/cmd/edit.js +82 -0
- package/src/cmd/incPri.js +82 -0
- package/src/cmd/lists.js +60 -0
- package/src/cmd/login.js +27 -0
- package/src/cmd/logout.js +31 -0
- package/src/cmd/ls.js +181 -0
- package/src/cmd/lsd.js +193 -0
- package/src/cmd/lsp.js +171 -0
- package/src/cmd/move.js +83 -0
- package/src/cmd/notes.js +150 -0
- package/src/cmd/planner.js +510 -0
- package/src/cmd/postpone.js +82 -0
- package/src/cmd/pri.js +82 -0
- package/src/cmd/remove.js +82 -0
- package/src/cmd/removeList.js +79 -0
- package/src/cmd/removeTags.js +85 -0
- package/src/cmd/renameList.js +80 -0
- package/src/cmd/reset.js +35 -0
- package/src/cmd/setUrl.js +99 -0
- package/src/cmd/tags.js +101 -0
- package/src/cmd/uncomp.js +82 -0
- package/src/cmd/url.js +92 -0
- package/src/cmd/whoami.js +36 -0
- package/src/interactive.js +65 -0
- package/src/utils/config.js +236 -0
- package/src/utils/filter.js +43 -0
- package/src/utils/finish.js +21 -0
- package/src/utils/index.js +10 -0
- package/src/utils/log.js +163 -0
- package/src/utils/login.js +69 -0
- package/src/utils/printIndicator.js +43 -0
- package/src/utils/prompt.js +126 -0
- package/src/utils/sort.js +283 -0
package/src/cmd/notes.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../utils/log.js');
|
|
4
|
+
const config = require('../utils/config.js');
|
|
5
|
+
const { prompt } = require('../utils/prompt.js');
|
|
6
|
+
const finish = require('../utils/finish.js');
|
|
7
|
+
const filter = require('../utils/filter')
|
|
8
|
+
const { USER_CONFIG } = require('../utils/config.js');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
let NOTES = [];
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This command displays a task's note
|
|
16
|
+
* @param args index
|
|
17
|
+
* @param env
|
|
18
|
+
*/
|
|
19
|
+
function action(args, env) {
|
|
20
|
+
|
|
21
|
+
// Reset Notes
|
|
22
|
+
NOTES = [];
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
// Prompt for task
|
|
26
|
+
if ( args.length < 1 ) {
|
|
27
|
+
prompt('Task:', _promptFinished);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Use provided args
|
|
31
|
+
else {
|
|
32
|
+
for ( let i = 0; i < args[0].length; i++ ) {
|
|
33
|
+
_process(args[0][i], i+1, args[0].length);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Process the returned answers
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
function _promptFinished(answers) {
|
|
45
|
+
for ( let i = 0; i < answers.length; i++ ) {
|
|
46
|
+
let answer = answers[i];
|
|
47
|
+
_process(answer[0], i+1, answers.length);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Process the request
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
function _process(index, count=1, max=1) {
|
|
57
|
+
|
|
58
|
+
// Display info
|
|
59
|
+
log.spinner.start("Getting Task(s)...");
|
|
60
|
+
|
|
61
|
+
// Get User
|
|
62
|
+
config.user(function(user) {
|
|
63
|
+
index = parseInt(index.trim());
|
|
64
|
+
|
|
65
|
+
// Get Task
|
|
66
|
+
let filterString = filter("hasNotes:true")
|
|
67
|
+
user.tasks.getTask(index, filterString, function(err, task) {
|
|
68
|
+
if ( err ) {
|
|
69
|
+
if ( err.code === -3 ) {
|
|
70
|
+
log.spinner.warn("Task #" + index + " does not have any notes or is not found.");
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
log.spinner.error("Could not get Task #" + index + " (" + err.msg + ")");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if ( task ) {
|
|
78
|
+
NOTES.push({
|
|
79
|
+
index: index,
|
|
80
|
+
name: task.name,
|
|
81
|
+
notes: task.notes
|
|
82
|
+
});
|
|
83
|
+
// console.log(task)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Finish
|
|
87
|
+
_processFinished(count, max);
|
|
88
|
+
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Request Callback
|
|
96
|
+
* @private
|
|
97
|
+
*/
|
|
98
|
+
function _processFinished(count, max) {
|
|
99
|
+
log.spinner.start("Getting Task [" + count + "/" + max + "]...");
|
|
100
|
+
|
|
101
|
+
// All tasks returned...
|
|
102
|
+
if ( count === max ) {
|
|
103
|
+
log.spinner.stop();
|
|
104
|
+
|
|
105
|
+
// Get Display Styles
|
|
106
|
+
let styles = config.get().styles;
|
|
107
|
+
|
|
108
|
+
// Print NOTES
|
|
109
|
+
for ( let i = 0; i < NOTES.length; i++ ) {
|
|
110
|
+
log.style(_pad(NOTES[i].index , NOTES.length), styles.index);
|
|
111
|
+
log.style(' ');
|
|
112
|
+
log.style(NOTES[i].name, true);
|
|
113
|
+
for (const note of NOTES[i].notes) {
|
|
114
|
+
log.style('Note: ',styles.due)
|
|
115
|
+
log.style(note.title ? note.title : '',true);
|
|
116
|
+
log('========');
|
|
117
|
+
log(note.body);
|
|
118
|
+
log();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return finish();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Pad the Index number with leading 0s
|
|
129
|
+
* @param index Task Index Number
|
|
130
|
+
* @param maxIndex Max Task Index
|
|
131
|
+
* @returns {string}
|
|
132
|
+
* @private
|
|
133
|
+
*/
|
|
134
|
+
function _pad(index, maxIndex) {
|
|
135
|
+
let max = maxIndex.toString().length;
|
|
136
|
+
let digits = index.toString().length;
|
|
137
|
+
let delta = max - digits;
|
|
138
|
+
for ( let i = 0; i < delta; i++ ) {
|
|
139
|
+
index = '0' + index;
|
|
140
|
+
}
|
|
141
|
+
return index;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
module.exports = {
|
|
146
|
+
command: 'notes [indices...]',
|
|
147
|
+
options: [],
|
|
148
|
+
description: 'Display the associated Notes of a Task',
|
|
149
|
+
action: action
|
|
150
|
+
};
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const df = require('dateformat');
|
|
4
|
+
const Table = require('cli-table3');
|
|
5
|
+
const ws = require('window-size');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const parseFilter = require('../utils/filter.js');
|
|
8
|
+
const config = require('../utils/config.js');
|
|
9
|
+
const log = require('../utils/log.js');
|
|
10
|
+
const sort = require('../utils/sort.js');
|
|
11
|
+
const finish = require('../utils/finish.js');
|
|
12
|
+
|
|
13
|
+
// Possible Start Arguments
|
|
14
|
+
const START_ARGS = ['sun', 'mon', 'today'];
|
|
15
|
+
const DEFAULT_START = START_ARGS[0];
|
|
16
|
+
const DEFAULT_WIDTH = 80;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* This command displays the tasks in a Weekly planner table. The week
|
|
21
|
+
* can start on either Sunday, Monday or the current day.
|
|
22
|
+
*/
|
|
23
|
+
function action(args, env) {
|
|
24
|
+
|
|
25
|
+
// Set filter and start arguments
|
|
26
|
+
let filter = parseFilter(args.length > 0 ? args[0].join(' ') : '');
|
|
27
|
+
let start = (env.start === undefined ? DEFAULT_START : env.start).toLowerCase();
|
|
28
|
+
let fixedWidth = (env.width === undefined ? undefined : parseInt(env.width));
|
|
29
|
+
|
|
30
|
+
// Check start arg
|
|
31
|
+
if ( START_ARGS.indexOf(start) === -1 ) {
|
|
32
|
+
log.error("ERROR: start arg not valid: " + start);
|
|
33
|
+
log("Must be one of: " + START_ARGS);
|
|
34
|
+
return finish();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Set start date
|
|
38
|
+
let startDate = new Date();
|
|
39
|
+
if ( start === 'sun' ) {
|
|
40
|
+
startDate.setDate(startDate.getDate() - startDate.getDay());
|
|
41
|
+
}
|
|
42
|
+
else if ( start === 'mon' ) {
|
|
43
|
+
startDate.setDate(startDate.getDate() - startDate.getDay() + 1);
|
|
44
|
+
}
|
|
45
|
+
startDate.setHours(0, 0, 0, 0);
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
// Get the User's Tasks
|
|
49
|
+
_getTasks(filter, function(tasks) {
|
|
50
|
+
|
|
51
|
+
// Display the Planner
|
|
52
|
+
_display(tasks, startDate, fixedWidth);
|
|
53
|
+
|
|
54
|
+
// Display the Overdue and No Due Tasks
|
|
55
|
+
_displayExtra(tasks, startDate, fixedWidth);
|
|
56
|
+
|
|
57
|
+
// Finish
|
|
58
|
+
finish();
|
|
59
|
+
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get the User's Tasks
|
|
67
|
+
* @param filter Filter String
|
|
68
|
+
* @param callback Callback function(tasks)
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
function _getTasks(filter, callback) {
|
|
72
|
+
|
|
73
|
+
// Get parsed filter
|
|
74
|
+
filter = parseFilter(filter);
|
|
75
|
+
|
|
76
|
+
// Start Spinner
|
|
77
|
+
log.spinner.start("Getting Tasks...");
|
|
78
|
+
|
|
79
|
+
// Get User
|
|
80
|
+
config.user(function(user) {
|
|
81
|
+
|
|
82
|
+
// Get User's Tasks
|
|
83
|
+
user.tasks.get(filter, function(err, tasks) {
|
|
84
|
+
if ( err ) {
|
|
85
|
+
log.spinner.error("Could not get tasks (" + err.msg + ")");
|
|
86
|
+
return finish();
|
|
87
|
+
}
|
|
88
|
+
log.spinner.stop();
|
|
89
|
+
return callback(tasks);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Display the Tasks in a Weekly Planner starting on the specified
|
|
99
|
+
* start date
|
|
100
|
+
* @param tasks User's Tasks
|
|
101
|
+
* @param start Start Date
|
|
102
|
+
* @param fixedWidth Fixed planner width, if provided
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
function _display(tasks, start, fixedWidth) {
|
|
106
|
+
|
|
107
|
+
// Header Titles
|
|
108
|
+
let headers = [];
|
|
109
|
+
|
|
110
|
+
// Width Information
|
|
111
|
+
let colMinWidths = []; // Array of each column's min width
|
|
112
|
+
let colMaxWidths = []; // Array of each column's max width
|
|
113
|
+
|
|
114
|
+
// Table Data
|
|
115
|
+
let data = [];
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
// Get Display Styles
|
|
119
|
+
let styles = config.get().styles;
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
// Parse each Date
|
|
123
|
+
for ( let i = 0; i < 7; i++ ) {
|
|
124
|
+
|
|
125
|
+
// Set current Date
|
|
126
|
+
let date = new Date(start);
|
|
127
|
+
date.setDate(date.getDate() + i);
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
// ==== DETERMINE HEADER ===== //
|
|
131
|
+
|
|
132
|
+
// Min Width for this column based on header text
|
|
133
|
+
let minWidth = 0;
|
|
134
|
+
|
|
135
|
+
// Header for TODAY
|
|
136
|
+
if ( _isToday(date) ) {
|
|
137
|
+
let text = "TODAY";
|
|
138
|
+
headers.push(
|
|
139
|
+
_style(text, styles.due + ".underline")
|
|
140
|
+
);
|
|
141
|
+
minWidth = _reset(text).length+2;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Header for other days
|
|
145
|
+
else {
|
|
146
|
+
let text = df(date, config.get().plannerDateformat);
|
|
147
|
+
headers.push(
|
|
148
|
+
_style(text, styles.due)
|
|
149
|
+
);
|
|
150
|
+
minWidth = _reset(text).length+2;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
// ==== DETERMINE COLUMN DATA ==== //
|
|
155
|
+
|
|
156
|
+
// Get Tasks DUE on Date
|
|
157
|
+
let dt = [];
|
|
158
|
+
for ( let j = 0; j < tasks.length; j++ ) {
|
|
159
|
+
let task = tasks[j];
|
|
160
|
+
if ( _sameDay(task.due, date) ) {
|
|
161
|
+
dt.push(task);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Generate column data
|
|
166
|
+
let lines = _displayTasks(dt);
|
|
167
|
+
|
|
168
|
+
// Add data
|
|
169
|
+
data.push(
|
|
170
|
+
lines.join(
|
|
171
|
+
_style('\n', 'reset')
|
|
172
|
+
)
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
// ==== DETERMINE COLUMN MIN & MAX WIDTHS ==== //
|
|
177
|
+
|
|
178
|
+
// Determine max line width
|
|
179
|
+
let maxWidth = minWidth;
|
|
180
|
+
for ( let i = 0; i < lines.length; i++ ) {
|
|
181
|
+
let l = _reset(lines[i]).length + 2;
|
|
182
|
+
if ( l > maxWidth ) {
|
|
183
|
+
maxWidth = l;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Set Col Widths
|
|
188
|
+
colMinWidths.push(minWidth);
|
|
189
|
+
colMaxWidths.push(maxWidth);
|
|
190
|
+
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
// ==== BUILD TABLE ==== //
|
|
195
|
+
|
|
196
|
+
let table = new Table({
|
|
197
|
+
colWidths: _calcWidths(colMinWidths, colMaxWidths, fixedWidth),
|
|
198
|
+
wordWrap: false,
|
|
199
|
+
head: headers,
|
|
200
|
+
style: {
|
|
201
|
+
head: []
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
table.push(data);
|
|
205
|
+
|
|
206
|
+
// Print Table
|
|
207
|
+
log(table.toString());
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Display an extra table displaying the tasks due before the start
|
|
214
|
+
* of the planner and tasks with no due date
|
|
215
|
+
* @param tasks User Tasks
|
|
216
|
+
* @param start Planner Start Date
|
|
217
|
+
* @param fixedWidth Fixed planner width, if provided
|
|
218
|
+
* @private
|
|
219
|
+
*/
|
|
220
|
+
function _displayExtra(tasks, start, fixedWidth) {
|
|
221
|
+
|
|
222
|
+
// Display Styles
|
|
223
|
+
let styles = config.get().styles;
|
|
224
|
+
|
|
225
|
+
// Get incomplete tasks that are due before the planner start and have no due date set
|
|
226
|
+
let overdue = [];
|
|
227
|
+
let nodue = [];
|
|
228
|
+
for ( let i = 0; i < tasks.length; i++ ) {
|
|
229
|
+
let task = tasks[i];
|
|
230
|
+
if ( task.due === undefined && !task.isCompleted ) {
|
|
231
|
+
nodue.push(task);
|
|
232
|
+
}
|
|
233
|
+
else if ( task.due < start && !task.isCompleted ) {
|
|
234
|
+
overdue.push(task);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Set Headers of Extra Table
|
|
239
|
+
let headers = [];
|
|
240
|
+
if ( overdue.length > 0 ) {
|
|
241
|
+
headers.push(
|
|
242
|
+
_style("Overdue Tasks", styles.due)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
if ( nodue.length > 0 ) {
|
|
246
|
+
headers.push(
|
|
247
|
+
_style("No Due Date", styles.due)
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Build Data
|
|
252
|
+
let data = [];
|
|
253
|
+
|
|
254
|
+
// Over Due Tasks
|
|
255
|
+
if ( overdue.length > 0 ) {
|
|
256
|
+
let overdueLines = _displayTasks(overdue);
|
|
257
|
+
data.push(
|
|
258
|
+
overdueLines.join(
|
|
259
|
+
_style('\n', 'reset')
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// No Due Tasks
|
|
265
|
+
if ( nodue.length > 0 ) {
|
|
266
|
+
let nodueLines = _displayTasks(nodue);
|
|
267
|
+
data.push(
|
|
268
|
+
nodueLines.join(
|
|
269
|
+
_style('\n', 'reset')
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Set column widths
|
|
275
|
+
let colWidths = [];
|
|
276
|
+
if ( fixedWidth !== undefined ) {
|
|
277
|
+
for ( let i = 0; i < headers.length; i++ ) {
|
|
278
|
+
colWidths[i] = Math.floor((fixedWidth/headers.length)-(headers.length-1));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Build Extra Table
|
|
283
|
+
let table = new Table({
|
|
284
|
+
head: headers,
|
|
285
|
+
style: { head: [] },
|
|
286
|
+
colWidths: colWidths
|
|
287
|
+
});
|
|
288
|
+
table.push(data);
|
|
289
|
+
|
|
290
|
+
// Print Extra Table
|
|
291
|
+
log(table.toString());
|
|
292
|
+
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Generate the Column Data displaying the provided tasks
|
|
298
|
+
* @param tasks Tasks to Display
|
|
299
|
+
* @returns {Array} Array of lines to display
|
|
300
|
+
* @private
|
|
301
|
+
*/
|
|
302
|
+
function _displayTasks(tasks) {
|
|
303
|
+
|
|
304
|
+
// Display Styles
|
|
305
|
+
let styles = config.get().styles;
|
|
306
|
+
|
|
307
|
+
// Sort by list, priority
|
|
308
|
+
tasks.sort(sort.tasks.ls);
|
|
309
|
+
|
|
310
|
+
// Lines to return
|
|
311
|
+
let lines = [];
|
|
312
|
+
|
|
313
|
+
// Output Tasks
|
|
314
|
+
let prevList = '';
|
|
315
|
+
for ( let j = 0; j < tasks.length; j++ ) {
|
|
316
|
+
let task = tasks[j];
|
|
317
|
+
|
|
318
|
+
// List Name
|
|
319
|
+
let list = task.list.name;
|
|
320
|
+
if ( prevList !== list ) {
|
|
321
|
+
lines.push(
|
|
322
|
+
_style(list + ":", styles.list)
|
|
323
|
+
);
|
|
324
|
+
prevList = list;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Task Line
|
|
328
|
+
let line = '';
|
|
329
|
+
|
|
330
|
+
// Completed Task
|
|
331
|
+
if ( task.isCompleted ) {
|
|
332
|
+
line += _style('x', styles.completed);
|
|
333
|
+
line += _style(' ', 'reset');
|
|
334
|
+
line += _style(task.name, styles.completed);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Incomplete Task
|
|
338
|
+
else {
|
|
339
|
+
let style = styles.priority[task.priority];
|
|
340
|
+
if ( task.priority > 0 ) {
|
|
341
|
+
line += _style(task.priority, style);
|
|
342
|
+
line += _style(' ', 'reset');
|
|
343
|
+
line += _style(task.name, style);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
line += _style(' ', 'reset');
|
|
347
|
+
line += _style(task.name, style);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Reset Coloring
|
|
352
|
+
line += _style('', 'reset');
|
|
353
|
+
|
|
354
|
+
// Add Line
|
|
355
|
+
lines.push(line);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Reset Coloring
|
|
359
|
+
lines.push(_style('', 'reset'));
|
|
360
|
+
|
|
361
|
+
return lines;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Calculate the optimum column widths given their desired min and max widths
|
|
367
|
+
* and the width of the console.
|
|
368
|
+
* @param colMinWidths array of min widths
|
|
369
|
+
* @param colMaxWidths array of max widths
|
|
370
|
+
* @param fixedWidth fixed planner display width
|
|
371
|
+
* @returns {Array} array of final widths
|
|
372
|
+
* @private
|
|
373
|
+
*/
|
|
374
|
+
function _calcWidths(colMinWidths, colMaxWidths, fixedWidth) {
|
|
375
|
+
|
|
376
|
+
// Total Width Available
|
|
377
|
+
let width = DEFAULT_WIDTH;
|
|
378
|
+
if ( fixedWidth !== undefined ) {
|
|
379
|
+
width = fixedWidth;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
try {
|
|
383
|
+
width = ws.width;
|
|
384
|
+
}
|
|
385
|
+
catch (exception) {}
|
|
386
|
+
}
|
|
387
|
+
let widthTotal = width - 8;
|
|
388
|
+
|
|
389
|
+
// Requested Total Width
|
|
390
|
+
let widthRequested = 0;
|
|
391
|
+
for ( let i = 0; i < colMaxWidths.length; i++ ) {
|
|
392
|
+
widthRequested += colMaxWidths[i];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Width to Reduce
|
|
396
|
+
let widthReduce = widthRequested > widthTotal ? widthRequested - widthTotal : 0;
|
|
397
|
+
|
|
398
|
+
// Columns with Overflow
|
|
399
|
+
let overflow = 0;
|
|
400
|
+
for ( let i = 0; i < colMinWidths.length; i++ ) {
|
|
401
|
+
if ( colMaxWidths[i] > colMinWidths[i] ) {
|
|
402
|
+
overflow++;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Final Column Widths
|
|
407
|
+
let colWidths = [];
|
|
408
|
+
|
|
409
|
+
// Calculate each columns width
|
|
410
|
+
for ( let i = 0; i < colMinWidths.length; i++ ) {
|
|
411
|
+
let min = colMinWidths[i];
|
|
412
|
+
let max = colMaxWidths[i];
|
|
413
|
+
|
|
414
|
+
if ( widthReduce === 0 ) {
|
|
415
|
+
colWidths.push(max);
|
|
416
|
+
}
|
|
417
|
+
else if ( max > min ) {
|
|
418
|
+
let w = max - Math.ceil(widthReduce/overflow);
|
|
419
|
+
if ( w < min ) {
|
|
420
|
+
w = min;
|
|
421
|
+
}
|
|
422
|
+
colWidths.push(w);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
colWidths.push(min);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return colWidths;
|
|
430
|
+
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
// ==== HELPER FUNCTIONS ==== //
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Check if the two Dates are the same day
|
|
441
|
+
* @param d1 Date 1
|
|
442
|
+
* @param d2 Date 2
|
|
443
|
+
* @returns {boolean}
|
|
444
|
+
* @private
|
|
445
|
+
*/
|
|
446
|
+
function _sameDay(d1, d2) {
|
|
447
|
+
if ( d1 === undefined || d2 === undefined ) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
return d1.getFullYear() === d2.getFullYear() &&
|
|
451
|
+
d1.getMonth() === d2.getMonth() &&
|
|
452
|
+
d1.getDate() === d2.getDate();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Check if the specified Date is today
|
|
457
|
+
* @param date Date
|
|
458
|
+
* @returns {boolean}
|
|
459
|
+
* @private
|
|
460
|
+
*/
|
|
461
|
+
function _isToday(date) {
|
|
462
|
+
return _sameDay(date, new Date());
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Style the Text using the specfied Chalk style
|
|
467
|
+
* @param text Text to Style
|
|
468
|
+
* @param style Chalk Style (ex: yellow.underline)
|
|
469
|
+
* @returns {string} Styled String
|
|
470
|
+
* @private
|
|
471
|
+
*/
|
|
472
|
+
function _style(text, style) {
|
|
473
|
+
if ( config.get().plain ) {
|
|
474
|
+
return text;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
let parts = style.split('.');
|
|
478
|
+
let c = chalk;
|
|
479
|
+
for ( let i = 0; i < parts.length; i++ ) {
|
|
480
|
+
c = c[parts[i]];
|
|
481
|
+
}
|
|
482
|
+
return c(text);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Remove color and style info from the text string
|
|
487
|
+
* @param text Text String
|
|
488
|
+
* @returns {string}
|
|
489
|
+
* @private
|
|
490
|
+
*/
|
|
491
|
+
function _reset(text) {
|
|
492
|
+
return text.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
module.exports = {
|
|
497
|
+
command: 'planner [filter...]',
|
|
498
|
+
options: [
|
|
499
|
+
{
|
|
500
|
+
option: "-s, --start <start>",
|
|
501
|
+
description: "Planner start day (sun, mon, or today)"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
option: "-w, --width <cols>",
|
|
505
|
+
description: "Set fixed planner display width (in number of columns)"
|
|
506
|
+
}
|
|
507
|
+
],
|
|
508
|
+
description: 'Display tasks in a weekly planner (--start: sun, mon, today)',
|
|
509
|
+
action: action
|
|
510
|
+
};
|