├── images ├── pomodoro_rest_status_sample.jpg ├── pomodoro_pause_status_sample.png └── pomodoro_working_status_sample.jpg ├── Pomodoro.sublime-settings ├── Default.sublime-commands ├── .github └── ISSUE_TEMPLATE.md ├── Main.sublime-menu ├── README.md └── pomodoro.py /images/pomodoro_rest_status_sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neway6655/Sublime-Pomodoro/HEAD/images/pomodoro_rest_status_sample.jpg -------------------------------------------------------------------------------- /images/pomodoro_pause_status_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neway6655/Sublime-Pomodoro/HEAD/images/pomodoro_pause_status_sample.png -------------------------------------------------------------------------------- /images/pomodoro_working_status_sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neway6655/Sublime-Pomodoro/HEAD/images/pomodoro_working_status_sample.jpg -------------------------------------------------------------------------------- /Pomodoro.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "workingMins": 25, 3 | "restingMins": 5, 4 | "longBreakWorkingCount": 4, 5 | "longBreakMins": 15, 6 | "autoStart": false 7 | } -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Pomodoro: Run Pomodoro", 4 | "command": "pomodoro", 5 | }, 6 | { 7 | "caption": "Pomodoro: Pause Pomodoro", 8 | "command": "pomodoro_pause" 9 | } 10 | ] -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * Issue description: 2 | 3 | * Expected behavior and actual behavior: 4 | 5 | * Steps to reproduce the problem: 6 | 7 | * Specifications like the operating system, and sublime version: 8 | 9 | * Other comments: 10 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "Pomodoro", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/Sublime-Pomodoro/Pomodoro.sublime-settings"}, 21 | "caption": "Settings – Default" 22 | }, 23 | { 24 | "command": "open_file", 25 | "args": {"file": "${packages}/User/Pomodoro.sublime-settings"}, 26 | "caption": "Settings – User" 27 | } 28 | ] 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pomodoro-Sublime-Plugin 2 | ========================= 3 | 4 | This is a sublime plugin which implements functions like pomodoro. 5 | 6 | Usage: 7 | ----------------------------- 8 | Add the line below to your **"Preferences: Key Bindings - User"** settings: 9 | { "keys": ["ctrl+shift+alt+p"], "command": "pomodoro" }, 10 | { "keys": ["ctrl+shift+9"], "command": "pomodoro_pause" } 11 | 12 | In **"Preferences: Package Settings - Pomodoro - Settings-Default"** are some arguments you can configure(all configurations have default values). We recommend you copy these values and paste in **"Preferences: Package Settings - Pomodoro - Settings-User"** 13 | 14 | * workingMins: configure your working time in minutes. 15 | * restingMins: configure your rest time in minutes. 16 | * longBreakWorkingCount: configure the number of working sessions before a long break. 17 | * longBreakMins: configure the long break time in minutes. 18 | * autoStart: configure whether pomodoro should be auto started or not once sublime was launched. 19 | 20 | You can stop pomodoro by pressing the binding key(e.g. "ctrl+shift+alt+p") again, and resume it by pressing it again one more time.:smiley: 21 | 22 | You can pause/unpause pomodoro by pressing "ctrl+shift+9". 23 | 24 | Preview: 25 | ----------------------------- 26 | *working progress*: 27 | 28 | ![](https://raw.githubusercontent.com/Neway6655/Sublime-Pomodoro/master/images/pomodoro_working_status_sample.jpg) 29 | 30 | *taking a break*: 31 | 32 | ![](https://raw.githubusercontent.com/Neway6655/Sublime-Pomodoro/master/images/pomodoro_rest_status_sample.jpg) 33 | 34 | *pause*: 35 | ![](https://raw.githubusercontent.com/Neway6655/Sublime-Pomodoro/master/images/pomodoro_pause_status_sample.png) -------------------------------------------------------------------------------- /pomodoro.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | import threading 4 | import functools 5 | import time 6 | 7 | ST_VERSION = 3000 if sublime.version() == '' else int(sublime.version()) 8 | 9 | try: 10 | from SubNotify.sub_notify import SubNotifyIsReadyCommand as Notify 11 | except Exception: 12 | class Notify(object): 13 | """Notify fallback.""" 14 | 15 | @classmethod 16 | def is_ready(cls): 17 | """Return false to effectively disable SubNotify.""" 18 | return False 19 | timeRecorder_thread = None 20 | 21 | 22 | def drawProgressbar(totalSize, currPos, charStartBar, charEndBar, charBackground, charPos): 23 | s = charStartBar 24 | for c in range(1, currPos - 1): 25 | s = s + charBackground 26 | s = s + charPos 27 | for c in range(currPos, totalSize): 28 | s = s + charBackground 29 | s = s + charEndBar 30 | return s 31 | 32 | 33 | def updateWorkingTimeStatus(kwargs): 34 | leftMins = kwargs.get('leftMins') 35 | totMins = kwargs.get('runningMins') 36 | current_pomodoro = kwargs.get('current_pomodoro') 37 | total_pomodoros = kwargs.get('total_pomodoros') 38 | sublime.status_message( 39 | 'Working time remaining: ' + str(leftMins) + 'mins | pomodoro: ' + 40 | str(current_pomodoro + 1) + '/' + str(total_pomodoros) + ' ' + 41 | drawProgressbar(totMins, totMins - leftMins + 1, '[', ']', '-', 'O') 42 | ) 43 | 44 | 45 | def updateRestingTimeStatus(kwargs): 46 | leftMins = kwargs.get('leftMins') 47 | totMins = kwargs.get('runningMins') 48 | current_pomodoro = kwargs.get('current_pomodoro') 49 | total_pomodoros = kwargs.get('total_pomodoros') 50 | if current_pomodoro == 0: 51 | current_pomodoro = total_pomodoros 52 | 53 | sublime.status_message( 54 | 'Resting time remaining: ' + str(leftMins) + 'mins ' + '| break: ' + 55 | str(current_pomodoro) + '/' + str(total_pomodoros) + ' ' + 56 | drawProgressbar(totMins, totMins - leftMins + 1, '[', ']', '-', 'O') 57 | ) 58 | 59 | 60 | def stopRecording(): 61 | sublime.status_message('') 62 | 63 | 64 | def pauseRecording(): 65 | sublime.status_message('Pomodoro Paused ||') 66 | time.sleep(1) 67 | sublime.status_message('') 68 | time.sleep(1) 69 | 70 | 71 | class TimeRecorder(threading.Thread): 72 | def __init__(self, view, workingMins, restingMins, longBreakWorkingCount, longBreakMins): 73 | super(TimeRecorder, self).__init__() 74 | self.view = view 75 | self.workingMins = workingMins 76 | self.restingMins = restingMins 77 | self.longBreakWorkingCount = longBreakWorkingCount 78 | self.longBreakMins = longBreakMins 79 | self.stopFlag = threading.Event() 80 | self.workingSessionCount = 0 81 | self.is_paused = False 82 | 83 | def recording(self, runningMins, displayCallback): 84 | leftMins = runningMins 85 | while leftMins > 1: 86 | 87 | for i in range(1, 60): 88 | while self.is_paused: 89 | pauseRecording() 90 | if self.stopped(): 91 | stopRecording() 92 | break 93 | kwargs = { 94 | 'runningMins': runningMins, 95 | 'leftMins': leftMins, 96 | 'current_pomodoro': self.workingSessionCount, 97 | 'total_pomodoros': self.longBreakWorkingCount 98 | } 99 | sublime.set_timeout(functools.partial(displayCallback, kwargs), 10) 100 | time.sleep(1) 101 | leftMins = leftMins - 1 102 | 103 | if leftMins == 1: 104 | for i in range(1, 12): 105 | while self.is_paused: 106 | pauseRecording() 107 | if self.stopped(): 108 | stopRecording() 109 | break 110 | kwargs = { 111 | 'runningMins': runningMins, 112 | 'leftMins': leftMins, 113 | 'current_pomodoro': self.workingSessionCount, 114 | 'total_pomodoros': self.longBreakWorkingCount 115 | } 116 | sublime.set_timeout(functools.partial(displayCallback, kwargs), 10) 117 | time.sleep(5) 118 | leftMins = leftMins - 1 119 | 120 | def longBreak(self, workingSessionCount): 121 | return workingSessionCount >= self.longBreakWorkingCount 122 | 123 | def run(self): 124 | while 1: 125 | if self.stopped(): 126 | stopRecording() 127 | time.sleep(2) 128 | continue 129 | 130 | self.recording(self.workingMins, updateWorkingTimeStatus) 131 | 132 | if self.stopped(): 133 | stopRecording() 134 | time.sleep(2) 135 | continue 136 | 137 | if Notify.is_ready(): 138 | sublime.run_command("sub_notify", {"title": "", "msg": "Hey, you are working too hard, take a rest."}) 139 | rest = True 140 | else: 141 | rest = sublime.ok_cancel_dialog('Hey, you are working too hard, take a rest.', 'OK') 142 | # increase work session count 143 | self.workingSessionCount += 1 144 | 145 | if rest: 146 | restingMins = self.restingMins 147 | if self.longBreak(self.workingSessionCount): 148 | restingMins = self.longBreakMins 149 | self.workingSessionCount = 0 150 | self.recording(restingMins, updateRestingTimeStatus) 151 | if self.stopped(): 152 | stopRecording() 153 | time.sleep(2) 154 | continue 155 | if Notify.is_ready(): 156 | sublime.run_command("sub_notify", {"title": "", "msg": "Come on, let's continue."}) 157 | work = True 158 | else: 159 | work = sublime.ok_cancel_dialog("Come on, let's continue.", 'OK') 160 | if not work: 161 | self.stop() 162 | time.sleep(2) 163 | 164 | def stop(self): 165 | self.stopFlag.set() 166 | 167 | def stopped(self): 168 | return self.stopFlag.isSet() 169 | 170 | def resume(self): 171 | self.stopFlag.clear() 172 | 173 | def pause(self): 174 | self.is_paused = not self.is_paused 175 | 176 | 177 | class PomodoroCommand(sublime_plugin.TextCommand): 178 | 179 | def run(self, edit, **kwargs): 180 | global timeRecorder_thread 181 | autoStart, workingMins, restingMins, longBreakWorkingCount, longBreakMins = load_settings() 182 | if timeRecorder_thread is None: 183 | timeRecorder_thread = TimeRecorder( 184 | self.view, workingMins, restingMins, longBreakWorkingCount, longBreakMins 185 | ) 186 | timeRecorder_thread.start() 187 | elif timeRecorder_thread.stopped(): 188 | timeRecorder_thread.resume() 189 | else: 190 | timeRecorder_thread.stop() 191 | 192 | 193 | class PomodoroPauseCommand(sublime_plugin.TextCommand): 194 | 195 | def run(self, edit, **kwargs): 196 | if timeRecorder_thread: 197 | timeRecorder_thread.pause() 198 | 199 | 200 | def load_settings(): 201 | s = sublime.load_settings("Pomodoro.sublime-settings") 202 | autoStart = s.get("autoStart", False) 203 | workingMins = s.get("workingMins", 25) 204 | restingMins = s.get("restingMins", 5) 205 | longBreakWorkingCount = s.get("longBreakWorkingCount", 4) 206 | longBreakMins = s.get("longBreakMins", 15) 207 | return autoStart, workingMins, restingMins, longBreakWorkingCount, longBreakMins 208 | 209 | 210 | def plugin_loaded(): 211 | autoStart, workingMins, restingMins, longBreakWorkingCount, longBreakMins = load_settings() 212 | if autoStart: 213 | sublime.active_window().run_command( 214 | 'pomodoro', 215 | ) 216 | 217 | 218 | if ST_VERSION < 3000: 219 | autoStart, workingMins, restingMins, longBreakWorkingCount, longBreakMins = load_settings() 220 | if autoStart: 221 | sublime.active_window().run_command( 222 | 'pomodoro', 223 | { 224 | 'workingMins': workingMins, 225 | "restingMins": restingMins, 226 | "longBreakWorkingCount": longBreakWorkingCount, 227 | "longBreakMins": longBreakMins 228 | } 229 | ) 230 | --------------------------------------------------------------------------------