| var fs = require('fs'); | ||
| var ini = require('ini'); | ||
| var moment = require('moment'); | ||
| var duration = require('./helpers').shortDuration; | ||
| var format = require('util').format; | ||
| /** | ||
| * Logs the given `pomodoro` to `file`. | ||
| * | ||
| * pomodoro == { | ||
| * reason: 'xx' | ||
| * duration: 30000 | ||
| * break: 5000 | ||
| * date: | ||
| * interrupted: false | ||
| * } | ||
| */ | ||
| var logger = module.exports = function(file, pomodoro) { | ||
| var data = logger.load(logger.read(file)) || {}; | ||
| var date = moment(pomodoro.date).format('YYYY-MM-DD ddd').toLowerCase(); | ||
| var time = moment(pomodoro.date).format('h:mma'); | ||
| var str = format("%s (%s%s%s)", | ||
| pomodoro.reason, | ||
| duration(pomodoro.duration), | ||
| (pomodoro['break'] ? (' + ' + duration(pomodoro['break'])) : ''), | ||
| (pomodoro.interrupted ? ', stopped' : '')); | ||
| if (!data[date]) data[date] = {}; | ||
| data[date][time] = str; | ||
| var output = logger.dump(data); | ||
| logger.write(file, output); | ||
| }; | ||
| logger.dump = function(obj) { | ||
| return ini.stringify(obj); | ||
| }; | ||
| logger.load = function(str) { | ||
| return ini.parse(str); | ||
| }; | ||
| /** | ||
| * Reads file | ||
| * @api internal | ||
| */ | ||
| logger.read = function(file) { | ||
| try { | ||
| return fs.readFileSync(file, 'utf-8'); | ||
| } catch(e) { | ||
| return ''; | ||
| } | ||
| }; | ||
| logger.write = function(file, output) { | ||
| fs.writeFileSync(file, output, { encoding: 'utf-8' }); | ||
| }; |
+15
| var c = require('./helpers').c; | ||
| var moment = require('moment'); | ||
| exports.info = function(msg) { | ||
| process.stdout.write(c(33,' > ')); | ||
| console.log(msg.replace(/\n/g, '\n ')); | ||
| }; | ||
| exports.now = function(msg) { | ||
| var dot = ' ⋅ '; | ||
| console.log(''); | ||
| exports.info(moment().format('HH:mma') + dot + msg); | ||
| console.log(''); | ||
| }; |
| require('./setup'); | ||
| var logger = require('../lib/logger'); | ||
| var fs = require('fs'); | ||
| var mins = 60 * 1000; | ||
| describe('logger', function() { | ||
| var data; | ||
| /** | ||
| * Stub out actual FS writing/reading | ||
| */ | ||
| beforeEach(function() { | ||
| data = ''; | ||
| sinon.stub(logger, 'write', function(file, newdata) { | ||
| data = newdata; | ||
| }); | ||
| sinon.stub(logger, 'read', function(file) { | ||
| return data; | ||
| }); | ||
| }); | ||
| afterEach(function() { | ||
| logger.read.restore(); | ||
| logger.write.restore(); | ||
| }); | ||
| /** | ||
| * Test | ||
| */ | ||
| it('should work fresh', function() { | ||
| logger('x.txt', { | ||
| reason: 'working', | ||
| duration: 35*mins, 'break': 5*mins, | ||
| date: moment('May 5, 2013 1:00 pm').toDate() | ||
| }); | ||
| var args = logger.write.firstCall.args; | ||
| assert.equal(args[0], 'x.txt'); | ||
| assert.jsonEqual(logger.load(args[1]), { | ||
| '2013-05-05 sun': { | ||
| '1:00pm': 'working (35m + 5m)' | ||
| } | ||
| }); | ||
| }); | ||
| it('no break', function() { | ||
| logger('x.txt', { | ||
| reason: 'working', | ||
| duration: 35*mins, 'break': 0, | ||
| date: moment('May 5, 2013 1:00 pm').toDate() | ||
| }); | ||
| var args = logger.write.firstCall.args; | ||
| assert.jsonEqual(logger.load(args[1]), { | ||
| '2013-05-05 sun': { | ||
| '1:00pm': 'working (35m)' | ||
| } | ||
| }); | ||
| }); | ||
| it('should consolidate', function() { | ||
| logger('x.txt', { | ||
| reason: 'working', | ||
| duration: 35*mins, 'break': 5*mins, | ||
| date: moment('May 5, 2013 3:00 pm').toDate() | ||
| }); | ||
| logger('x.txt', { | ||
| reason: 'working again', | ||
| duration: 30*mins, 'break': 5*mins, | ||
| date: moment('May 5, 2013 3:30 pm').toDate(), | ||
| interrupted: true | ||
| }); | ||
| logger('x.txt', { | ||
| reason: 'also working', | ||
| duration: 25*mins, 'break': 5*mins, | ||
| date: moment('May 6, 2013 5:00 am').toDate() | ||
| }); | ||
| var args = logger.write.thirdCall.args; | ||
| assert.jsonEqual(logger.load(args[1]), { | ||
| '2013-05-05 sun': { | ||
| '3:00pm': 'working (35m + 5m)', | ||
| '3:30pm': 'working again (30m + 5m, stopped)' | ||
| }, | ||
| '2013-05-06 mon': { | ||
| '5:00am': 'also working (25m + 5m)' | ||
| } | ||
| }); | ||
| }); | ||
| }); |
+4
-0
@@ -0,1 +1,5 @@ | ||
| ## v1.0.6 - June 18, 2013 | ||
| * Logging via `pomojs -l <file>`. | ||
| ## v1.0.5 - June 18, 2013 | ||
@@ -2,0 +6,0 @@ |
+4
-0
@@ -49,2 +49,6 @@ var _ = require('underscore'); | ||
| exports.shortDuration = function(n, suffix) { | ||
| return exports.duration(n).replace(/ .*$/, suffix || ''); | ||
| }; | ||
| /** | ||
@@ -51,0 +55,0 @@ * Copy to clipboard |
+3
-2
@@ -42,3 +42,4 @@ var moment = require('moment'); | ||
| Timer.prototype.elapsed = function() { | ||
| return moment.duration(+this.now() - this.startDate) || 0.0; | ||
| if (!this.startDate) return 0.0; | ||
| return moment.duration(Math.min(+this.now() - this.startDate, this.duration)) || 0.0; | ||
| }; | ||
@@ -96,3 +97,3 @@ | ||
| Timer.prototype.isLapsed = function() { | ||
| return +this.elapsed() > this.duration; | ||
| return +this.elapsed() >= this.duration; | ||
| }; | ||
@@ -99,0 +100,0 @@ |
+7
-5
@@ -12,5 +12,7 @@ var fs = require('fs'); | ||
| fs.writeFile(fn, str, function(err) { | ||
| if (err) throw err; | ||
| }); | ||
| // Do it synchronously at the end to ensure sequential-ness | ||
| if (+remaining < 5000) | ||
| fs.writeFileSync(fn, str); | ||
| else | ||
| fs.writeFile(fn, str, function(err) { if (err) throw(err); }); | ||
| }; | ||
@@ -22,3 +24,3 @@ | ||
| if (percent === null) return ''; | ||
| if (percent === null) return ' '; | ||
| if (+remaining === 0 && mode === 'break') return ''; | ||
@@ -45,3 +47,3 @@ | ||
| if (remaining > 0) | ||
| if (+remaining > 0 && elapsed > 0) | ||
| dur = '#[fg='+color+']' + | ||
@@ -48,0 +50,0 @@ duration(remaining).replace(/ .*$/, ''); |
+7
-4
@@ -5,9 +5,11 @@ { | ||
| "keywords": [ | ||
| "timer", "countdown", "stopwatch" | ||
| "timer", | ||
| "countdown", | ||
| "stopwatch" | ||
| ], | ||
| "author": "Rico Sta. Cruz <hi@ricostacruz.com>", | ||
| "version": "1.0.5", | ||
| "version": "1.0.6", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/rstacruz/pomo.git" | ||
| "url": "https://github.com/rstacruz/pomo.js.git" | ||
| }, | ||
@@ -30,4 +32,5 @@ "scripts": { | ||
| "underscore": "~1.4.4", | ||
| "q": "~0.9.6" | ||
| "q": "~0.9.6", | ||
| "ini": "~1.1.0" | ||
| } | ||
| } |
+39
-3
@@ -14,7 +14,9 @@ # Pomo.js | ||
| * Command-line goodness | ||
| * Command-line goodness (just type `pomojs`) | ||
| * Configurable work and break durations (`pomojs --work 10 --break 2`) | ||
| * Announces via text-to-speech ("5 minutes to go!") | ||
| * Growls | ||
| * Tmux support | ||
| * Growls (via growlnotify) | ||
| * No support for long breaks (this is a feature. problem?) | ||
| * Tmux support (status bar integration) | ||
| * Optional logging | ||
@@ -34,2 +36,36 @@ ### Requirements | ||
| ### Logging | ||
| Invoke it with `pomojs -l ~/.pomo.log` to log any pomodoros. Log file looks like | ||
| this: | ||
| ``` ini | ||
| [2013-06-17 mon] | ||
| 6:14am = work on things (25m + 5m) | ||
| 7:05am = do great stuff (25m + 2m, stopped) | ||
| [2013-06-18 tue] | ||
| 6:14am = eat pizza (25m + 5m) | ||
| ``` | ||
| ### Saving your settings | ||
| Add this to your shell config, so that the next time you can invoke `pomo` with | ||
| preset settings: | ||
| ``` | ||
| # ~/.bash_profile | ||
| alias pomo="pomojs --log ~/.pomo.log --tmux" | ||
| ``` | ||
| Even add more presets: | ||
| ``` sh | ||
| # long-break pomodoro | ||
| alias longpomo="pomo -b 20" | ||
| # 10-minute pomodoro | ||
| alias minipomo="pomo -w 10" | ||
| ``` | ||
| ### Also see | ||
@@ -36,0 +72,0 @@ |
+4
-0
@@ -24,2 +24,6 @@ global.moment = require('moment'); | ||
| assert.jsonEqual = function(left, right) { | ||
| return assert.equal(JSON.stringify(left), JSON.stringify(right)); | ||
| }; | ||
| /** | ||
@@ -26,0 +30,0 @@ * 2 * minutes |
+10
-0
@@ -27,2 +27,12 @@ require('./setup'); | ||
| it(".elapsed() beyond", function() { | ||
| timer = makeTimer({ mins: 1, elapsed: 1234*secs }); | ||
| assert.equal(+timer.elapsed(), 60*secs); | ||
| }); | ||
| it(".elapsed() before starting", function() { | ||
| timer = new Timer(30); | ||
| assert.equal(+timer.elapsed(), 0); | ||
| }); | ||
| it(".remaining()", function() { | ||
@@ -29,0 +39,0 @@ timer = makeTimer({ mins: 1.1, elapsed: 6*secs }); |
-15
| var c = require('./helpers').c; | ||
| var moment = require('moment'); | ||
| exports.info = function(msg) { | ||
| process.stdout.write(c(33,' > ')); | ||
| console.log(msg.replace(/\n/g, '\n ')); | ||
| }; | ||
| exports.now = function(msg) { | ||
| var dot = ' ⋅ '; | ||
| console.log(''); | ||
| exports.info(moment().format('HH:mma') + dot + msg); | ||
| console.log(''); | ||
| }; |
Sorry, the diff of this file is not supported yet
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
38165
16.29%17
13.33%626
30.96%83
76.6%5
25%5
66.67%+ Added
+ Added