├── .gitignore ├── .no-sublime-package ├── Color Scheme ├── light-orgmode.tmTheme └── orgmode.tmTheme ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Default.sublime-commands ├── LICENSE ├── Main.sublime-menu ├── README.md ├── Symbol List.tmPreferences ├── help_it.py ├── images ├── screenshot1.png └── screenshot2.png ├── messages.json ├── messages ├── 1.7.0.org ├── 1.7.4.org ├── 1.7.8.org ├── 1.9.0.org └── install.org ├── navigation_history.py ├── orgmode.py ├── orgmode.sublime-settings ├── orgmode.tmLanguage ├── orgmode_store.py ├── packages.json ├── resolver ├── __init__.py ├── abstract.py ├── crucible.py ├── email.py ├── fisheye.py ├── http.py ├── https.py ├── jira.py ├── local_file.py ├── prompt.py └── redmine.py └── snippets ├── break.sublime-snippet ├── checkbox_checked.sublime-snippet ├── checkbox_summary.sublime-snippet ├── checkbox_unchecked.sublime-snippet ├── code.sublime-snippet ├── extlink.sublime-snippet ├── followup.sublime-snippet ├── headline.sublime-snippet ├── headline2.sublime-snippet ├── headline3.sublime-snippet ├── intlink.sublime-snippet ├── intlink2.sublime-snippet ├── multitag.sublime-snippet ├── page.sublime-snippet ├── sumup.sublime-snippet ├── tack.sublime-snippet ├── tack_checkbox_checked.sublime-snippet ├── tack_checkbox_unchecked.sublime-snippet ├── tack_checkbox_unchecked_extlink.sublime-snippet ├── tack_done.sublime-snippet ├── tack_todo.sublime-snippet ├── tack_working.sublime-snippet └── tag.sublime-snippet /.gitignore: -------------------------------------------------------------------------------- 1 | # Can ignore specific files 2 | .DS_Store 3 | *.pyc 4 | *.cache 5 | *.bak -------------------------------------------------------------------------------- /.no-sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielmagnussons/orgmode/73d52ba15a39e0c0649ed268ca1f268800a990aa/.no-sublime-package -------------------------------------------------------------------------------- /Color Scheme/light-orgmode.tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Monokai inverse 7 | settings 8 | 9 | 10 | settings 11 | 12 | background 13 | #D8D7DD 14 | caret 15 | #07070F 16 | foreground 17 | #07070D 18 | invisibles 19 | #C4C5CD 20 | lineHighlight 21 | #C1C2CD 22 | selection 23 | #B6B7C1 24 | findHighlight 25 | #00186D 26 | findHighlightForeground 27 | #FFFFFF 28 | selectionBorder 29 | #DDDDE7 30 | activeGuide 31 | #62AAF0 32 | 33 | bracketsForeground 34 | #07070D 35 | bracketsOptions 36 | underline 37 | 38 | bracketContentsForeground 39 | #07070D 40 | bracketContentsOptions 41 | underline 42 | 43 | tagsOptions 44 | stippled_underline 45 | 46 | 47 | 48 | name 49 | Comment 50 | scope 51 | comment 52 | settings 53 | 54 | foreground 55 | #8A8EA1 56 | 57 | 58 | 59 | name 60 | String 61 | scope 62 | string 63 | settings 64 | 65 | foreground 66 | #19248B 67 | 68 | 69 | 70 | name 71 | Number 72 | scope 73 | constant.numeric 74 | settings 75 | 76 | foreground 77 | #517E00 78 | 79 | 80 | 81 | 82 | name 83 | Built-in constant 84 | scope 85 | constant.language 86 | settings 87 | 88 | foreground 89 | #517E00 90 | 91 | 92 | 93 | name 94 | User-defined constant 95 | scope 96 | constant.character, constant.other 97 | settings 98 | 99 | foreground 100 | #517E00 101 | 102 | 103 | 104 | name 105 | Variable 106 | scope 107 | variable 108 | settings 109 | 110 | fontStyle 111 | 112 | 113 | 114 | 115 | name 116 | Keyword 117 | scope 118 | keyword 119 | settings 120 | 121 | foreground 122 | #06D98D 123 | 124 | 125 | 126 | name 127 | Storage 128 | scope 129 | storage 130 | settings 131 | 132 | fontStyle 133 | 134 | foreground 135 | #06D98D 136 | 137 | 138 | 139 | name 140 | Storage type 141 | scope 142 | storage.type 143 | settings 144 | 145 | fontStyle 146 | italic 147 | foreground 148 | #992610 149 | 150 | 151 | 152 | name 153 | Class name 154 | scope 155 | entity.name.class 156 | settings 157 | 158 | fontStyle 159 | underline 160 | foreground 161 | #591DD1 162 | 163 | 164 | 165 | name 166 | Inherited class 167 | scope 168 | entity.other.inherited-class 169 | settings 170 | 171 | fontStyle 172 | italic underline 173 | foreground 174 | #591DD1 175 | 176 | 177 | 178 | name 179 | Function name 180 | scope 181 | entity.name.function 182 | settings 183 | 184 | fontStyle 185 | 186 | foreground 187 | #591DD1 188 | 189 | 190 | 191 | name 192 | Function argument 193 | scope 194 | variable.parameter 195 | settings 196 | 197 | fontStyle 198 | italic 199 | foreground 200 | #0268E0 201 | 202 | 203 | 204 | name 205 | Tag name 206 | scope 207 | entity.name.tag 208 | settings 209 | 210 | fontStyle 211 | 212 | foreground 213 | #06D98D 214 | 215 | 216 | 217 | name 218 | Tag attribute 219 | scope 220 | entity.other.attribute-name 221 | settings 222 | 223 | fontStyle 224 | 225 | foreground 226 | #591DD1 227 | 228 | 229 | 230 | name 231 | Library function 232 | scope 233 | support.function 234 | settings 235 | 236 | fontStyle 237 | 238 | foreground 239 | #992610 240 | 241 | 242 | 243 | name 244 | Library constant 245 | scope 246 | support.constant 247 | settings 248 | 249 | fontStyle 250 | 251 | foreground 252 | #992610 253 | 254 | 255 | 256 | name 257 | Library class/type 258 | scope 259 | support.type, support.class 260 | settings 261 | 262 | fontStyle 263 | italic 264 | foreground 265 | #992610 266 | 267 | 268 | 269 | name 270 | Library variable 271 | scope 272 | support.other.variable 273 | settings 274 | 275 | fontStyle 276 | 277 | 278 | 279 | 280 | name 281 | Invalid 282 | scope 283 | invalid 284 | settings 285 | 286 | background 287 | #06D98D 288 | fontStyle 289 | 290 | foreground 291 | #07070F 292 | 293 | 294 | 295 | name 296 | Invalid deprecated 297 | scope 298 | invalid.deprecated 299 | settings 300 | 301 | background 302 | #517E00 303 | foreground 304 | #07070F 305 | 306 | 307 | 308 | name 309 | JSON String 310 | scope 311 | meta.structure.dictionary.json string.quoted.double.json 312 | settings 313 | 314 | foreground 315 | #30303D 316 | 317 | 318 | 319 | 320 | name 321 | diff.header 322 | scope 323 | meta.diff, meta.diff.header 324 | settings 325 | 326 | foreground 327 | #8A8EA1 328 | 329 | 330 | 331 | name 332 | diff.deleted 333 | scope 334 | markup.deleted 335 | settings 336 | 337 | foreground 338 | #06D98D 339 | 340 | 341 | 342 | name 343 | diff.inserted 344 | scope 345 | markup.inserted 346 | settings 347 | 348 | foreground 349 | #591DD1 350 | 351 | 352 | 353 | name 354 | diff.changed 355 | scope 356 | markup.changed 357 | settings 358 | 359 | foreground 360 | #19248B 361 | 362 | 363 | 364 | 365 | scope 366 | constant.numeric.line-number.find-in-files - match 367 | settings 368 | 369 | foreground 370 | #517E00 371 | 372 | 373 | 374 | scope 375 | entity.name.filename.find-in-files 376 | settings 377 | 378 | foreground 379 | #19248B 380 | 381 | 382 | 383 | 384 | name 385 | orgmode link 386 | scope 387 | orgmode.link 388 | settings 389 | 390 | foreground 391 | #FB9A4B 392 | fontStyle 393 | underline 394 | 395 | 396 | 397 | name 398 | orgmode page 399 | scope 400 | orgmode.page 401 | settings 402 | 403 | foreground 404 | #000055 405 | 406 | 407 | 408 | name 409 | orgmode break 410 | scope 411 | orgmode.break 412 | settings 413 | 414 | foreground 415 | #005555 416 | 417 | 418 | 419 | name 420 | orgmode headline 421 | scope 422 | orgmode.headline 423 | settings 424 | 425 | foreground 426 | #610000 427 | 428 | 429 | 430 | name 431 | orgmode tack 432 | scope 433 | orgmode.tack 434 | settings 435 | 436 | foreground 437 | #000055 438 | 439 | 440 | 441 | name 442 | orgmode follow up 443 | scope 444 | orgmode.follow_up 445 | settings 446 | 447 | foreground 448 | #000055 449 | 450 | 451 | 452 | name 453 | orgmode checkbox 454 | scope 455 | orgmode.checkbox 456 | settings 457 | 458 | foreground 459 | #000055 460 | 461 | 462 | 463 | name 464 | orgmode checkbox summary 465 | scope 466 | orgmode.checkbox.summary 467 | settings 468 | 469 | foreground 470 | #000055 471 | 472 | 473 | 474 | name 475 | orgmode tags 476 | scope 477 | orgmode.tags 478 | settings 479 | 480 | foreground 481 | #550055 482 | 483 | 484 | 485 | 486 | uuid 487 | D8D5E82E-3D5B-46B5-B38E-8C841C21347D 488 | 489 | 490 | -------------------------------------------------------------------------------- /Color Scheme/orgmode.tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Monokai Bright 7 | settings 8 | 9 | 10 | settings 11 | 12 | background 13 | #272822 14 | caret 15 | #F8F8F0 16 | foreground 17 | #F8F8F2 18 | invisibles 19 | #3B3A32 20 | lineHighlight 21 | #3E3D32 22 | selection 23 | #9D550F 24 | selectionForeground 25 | #fffff8 26 | inactiveSelection 27 | #bbbbbb 28 | inactiveSelectionForeground 29 | #222222 30 | findHighlight 31 | #FFE792 32 | findHighlightForeground 33 | #000000 34 | activeGuide 35 | #9D550FB0 36 | 37 | bracketsForeground 38 | #F8F8F2A5 39 | bracketsOptions 40 | underline 41 | 42 | bracketContentsForeground 43 | #F8F8F2A5 44 | bracketContentsOptions 45 | underline 46 | 47 | tagsOptions 48 | stippled_underline 49 | 50 | 51 | 52 | name 53 | Comment 54 | scope 55 | comment 56 | settings 57 | 58 | foreground 59 | #75715E 60 | 61 | 62 | 63 | name 64 | String 65 | scope 66 | string 67 | settings 68 | 69 | foreground 70 | #E6DB74 71 | 72 | 73 | 74 | name 75 | Number 76 | scope 77 | constant.numeric 78 | settings 79 | 80 | foreground 81 | #AE81FF 82 | 83 | 84 | 85 | name 86 | Built-in constant 87 | scope 88 | constant.language 89 | settings 90 | 91 | foreground 92 | #AE81FF 93 | 94 | 95 | 96 | name 97 | User-defined constant 98 | scope 99 | constant.character, constant.other 100 | settings 101 | 102 | foreground 103 | #AE81FF 104 | 105 | 106 | 107 | name 108 | Variable 109 | scope 110 | variable 111 | settings 112 | 113 | fontStyle 114 | 115 | 116 | 117 | 118 | name 119 | Keyword 120 | scope 121 | keyword 122 | settings 123 | 124 | foreground 125 | #F92672 126 | 127 | 128 | 129 | name 130 | Storage 131 | scope 132 | storage 133 | settings 134 | 135 | fontStyle 136 | 137 | foreground 138 | #F92672 139 | 140 | 141 | 142 | name 143 | Storage type 144 | scope 145 | storage.type 146 | settings 147 | 148 | fontStyle 149 | italic 150 | foreground 151 | #66D9EF 152 | 153 | 154 | 155 | name 156 | Class name 157 | scope 158 | entity.name.class 159 | settings 160 | 161 | fontStyle 162 | underline 163 | foreground 164 | #A6E22E 165 | 166 | 167 | 168 | name 169 | Inherited class 170 | scope 171 | entity.other.inherited-class 172 | settings 173 | 174 | fontStyle 175 | italic underline 176 | foreground 177 | #A6E22E 178 | 179 | 180 | 181 | name 182 | Function name 183 | scope 184 | entity.name.function 185 | settings 186 | 187 | fontStyle 188 | 189 | foreground 190 | #A6E22E 191 | 192 | 193 | 194 | name 195 | Function argument 196 | scope 197 | variable.parameter 198 | settings 199 | 200 | fontStyle 201 | italic 202 | foreground 203 | #FD971F 204 | 205 | 206 | 207 | name 208 | Tag name 209 | scope 210 | entity.name.tag 211 | settings 212 | 213 | fontStyle 214 | 215 | foreground 216 | #F92672 217 | 218 | 219 | 220 | name 221 | Tag attribute 222 | scope 223 | entity.other.attribute-name 224 | settings 225 | 226 | fontStyle 227 | 228 | foreground 229 | #A6E22E 230 | 231 | 232 | 233 | name 234 | Library function 235 | scope 236 | support.function 237 | settings 238 | 239 | fontStyle 240 | 241 | foreground 242 | #66D9EF 243 | 244 | 245 | 246 | name 247 | Library constant 248 | scope 249 | support.constant 250 | settings 251 | 252 | fontStyle 253 | 254 | foreground 255 | #66D9EF 256 | 257 | 258 | 259 | name 260 | Library class/type 261 | scope 262 | support.type, support.class 263 | settings 264 | 265 | fontStyle 266 | italic 267 | foreground 268 | #66D9EF 269 | 270 | 271 | 272 | name 273 | Library variable 274 | scope 275 | support.other.variable 276 | settings 277 | 278 | fontStyle 279 | 280 | 281 | 282 | 283 | name 284 | Invalid 285 | scope 286 | invalid 287 | settings 288 | 289 | background 290 | #F92672 291 | fontStyle 292 | 293 | foreground 294 | #F8F8F0 295 | 296 | 297 | 298 | name 299 | Invalid deprecated 300 | scope 301 | invalid.deprecated 302 | settings 303 | 304 | background 305 | #AE81FF 306 | foreground 307 | #F8F8F0 308 | 309 | 310 | 311 | name 312 | JSON String 313 | scope 314 | meta.structure.dictionary.json string.quoted.double.json 315 | settings 316 | 317 | foreground 318 | #CFCFC2 319 | 320 | 321 | 322 | 323 | name 324 | diff.header 325 | scope 326 | meta.diff, meta.diff.header 327 | settings 328 | 329 | foreground 330 | #75715E 331 | 332 | 333 | 334 | name 335 | diff.deleted 336 | scope 337 | markup.deleted 338 | settings 339 | 340 | foreground 341 | #F92672 342 | 343 | 344 | 345 | name 346 | diff.inserted 347 | scope 348 | markup.inserted 349 | settings 350 | 351 | foreground 352 | #A6E22E 353 | 354 | 355 | 356 | name 357 | diff.changed 358 | scope 359 | markup.changed 360 | settings 361 | 362 | foreground 363 | #E6DB74 364 | 365 | 366 | 367 | 368 | scope 369 | constant.numeric.line-number.find-in-files - match 370 | settings 371 | 372 | foreground 373 | #AE81FFA0 374 | 375 | 376 | 377 | scope 378 | entity.name.filename.find-in-files 379 | settings 380 | 381 | foreground 382 | #E6DB74 383 | 384 | 385 | 386 | name 387 | orgmode link 388 | scope 389 | orgmode.link 390 | settings 391 | 392 | foreground 393 | #FB9A4B 394 | fontStyle 395 | underline 396 | 397 | 398 | 399 | name 400 | orgmode page 401 | scope 402 | orgmode.page 403 | settings 404 | 405 | foreground 406 | #FFFFAA 407 | 408 | 409 | 410 | name 411 | orgmode break 412 | scope 413 | orgmode.break 414 | settings 415 | 416 | foreground 417 | #FFAAAA 418 | 419 | 420 | 421 | name 422 | orgmode headline 423 | scope 424 | orgmode.headline 425 | settings 426 | 427 | foreground 428 | #9EFFFF 429 | 430 | 431 | 432 | name 433 | orgmode tack 434 | scope 435 | orgmode.tack 436 | settings 437 | 438 | foreground 439 | #FFFFAA 440 | 441 | 442 | 443 | name 444 | orgmode follow up 445 | scope 446 | orgmode.follow_up 447 | settings 448 | 449 | foreground 450 | #FFFFAA 451 | 452 | 453 | 454 | name 455 | orgmode checkbox 456 | scope 457 | orgmode.checkbox 458 | settings 459 | 460 | foreground 461 | #FFFFAA 462 | 463 | 464 | 465 | name 466 | orgmode checkbox summary 467 | scope 468 | orgmode.checkbox.summary 469 | settings 470 | 471 | foreground 472 | #FFFFAA 473 | 474 | 475 | 476 | name 477 | orgmode tags 478 | scope 479 | orgmode.tags 480 | settings 481 | 482 | foreground 483 | #AAFFAA 484 | 485 | 486 | 487 | 488 | uuid 489 | D8D5E82E-3D5B-46B5-B38E-8C841C21347E 490 | 491 | 492 | 493 | 494 | 495 | -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | /* Orgmode */ 3 | { "keys": ["enter"], "command": "orgmode_toggle_checkbox", "context": 4 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.checkbox" }] 5 | }, 6 | { "keys": ["enter"], "command": "orgmode_recalc_checkbox_summary", "context": 7 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.checkbox.summary" }] 8 | }, 9 | { "keys": ["enter"], "command": "orgmode_open_link", "context": 10 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.link" }] 11 | }, 12 | { "keys": ["enter"], "command": "orgmode_cycle_internal_link", "context": 13 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.link.internal" }] 14 | }, 15 | { "keys": ["enter"], "command": "orgmode_cycle_todo", "context": 16 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.todo" }] 17 | }, 18 | 19 | /* Navigation */ 20 | { "keys": ["alt+left"], "command": "navigation_history_back"}, 21 | { "keys": ["alt+right"], "command": "navigation_history_forward"}, 22 | 23 | /* Helpit */ 24 | { "keys": ["alt+f1"], "command": "help_it" }, 25 | 26 | /* Fold headlines */ 27 | { "keys": ["tab"], "command": "orgmode_folding", "context": 28 | [ 29 | { "key": "selector", "operator": "equal", "operand": "orgmode.headline" } 30 | ] 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | /* Orgmode */ 3 | { "keys": ["enter"], "command": "orgmode_toggle_checkbox", "context": 4 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.checkbox" }] 5 | }, 6 | { "keys": ["enter"], "command": "orgmode_recalc_checkbox_summary", "context": 7 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.checkbox.summary" }] 8 | }, 9 | { "keys": ["enter"], "command": "orgmode_open_link", "context": 10 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.link" }] 11 | }, 12 | { "keys": ["enter"], "command": "orgmode_cycle_internal_link", "context": 13 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.link.internal" }] 14 | }, 15 | { "keys": ["enter"], "command": "orgmode_cycle_todo", "context": 16 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.todo" }] 17 | }, 18 | 19 | /* Navigation */ 20 | /* 21 | { "keys": ["super+alt+left"], "command": "navigation_history_back"}, 22 | { "keys": ["super+alt+right"], "command": "navigation_history_forward"}, 23 | */ 24 | 25 | /* Helpit */ 26 | { "keys": ["alt+f1"], "command": "help_it" }, 27 | 28 | /* Fold headlines */ 29 | { "keys": ["tab"], "command": "orgmode_folding", "context": 30 | [ 31 | { "key": "selector", "operator": "equal", "operand": "orgmode.headline" } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | /* Orgmode */ 3 | { "keys": ["enter"], "command": "orgmode_toggle_checkbox", "context": 4 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.checkbox" }] 5 | }, 6 | { "keys": ["enter"], "command": "orgmode_recalc_checkbox_summary", "context": 7 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.checkbox.summary" }] 8 | }, 9 | { "keys": ["enter"], "command": "orgmode_open_link", "context": 10 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.link" }] 11 | }, 12 | { "keys": ["enter"], "command": "orgmode_cycle_internal_link", "context": 13 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.link.internal" }] 14 | }, 15 | { "keys": ["enter"], "command": "orgmode_cycle_todo", "context": 16 | [{ "key": "selector", "operator": "equal", "operand": "orgmode.todo" }] 17 | }, 18 | 19 | /* Navigation */ 20 | { "keys": ["alt+left"], "command": "navigation_history_back"}, 21 | { "keys": ["alt+right"], "command": "navigation_history_forward"}, 22 | 23 | /* Helpit */ 24 | { "keys": ["alt+f1"], "command": "help_it" }, 25 | 26 | /* Fold headlines */ 27 | { "keys": ["tab"], "command": "orgmode_folding", "context": 28 | [ 29 | { "key": "selector", "operator": "equal", "operand": "orgmode.headline" } 30 | ] 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences: orgmode Settings – Default", 4 | "command": "open_file", 5 | "args": { 6 | "file": "${packages}/orgmode/orgmode.sublime-settings" 7 | } 8 | }, 9 | { 10 | "caption": "Preferences: orgmode Settings – User", 11 | "command": "open_file", 12 | "args": { 13 | "file": "${packages}/User/orgmode.sublime-settings" 14 | } 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2011 Oktay Acikalin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "mnemonic": "n", 4 | "caption": "Preferences", 5 | "id": "preferences", 6 | "children": [ 7 | { 8 | "mnemonic": "P", 9 | "caption": "Package Settings", 10 | "id": "package-settings", 11 | "children": [ 12 | { 13 | "caption": "orgmode", 14 | "children": [ 15 | { 16 | "caption": "Readme.org", 17 | "args": { 18 | "file": "${packages}/orgmode/messages/install.org" 19 | }, 20 | "command": "open_file" 21 | }, 22 | { 23 | "caption": "Settings – Default", 24 | "args": { 25 | "file": "${packages}/orgmode/orgmode.sublime-settings" 26 | }, 27 | "command": "open_file" 28 | }, 29 | { 30 | "caption": "Settings – User", 31 | "args": { 32 | "file": "${packages}/User/orgmode.sublime-settings" 33 | }, 34 | "command": "open_file" 35 | }, 36 | { 37 | "caption": "-" 38 | } 39 | ] 40 | } 41 | ] 42 | } 43 | ] 44 | } 45 | ] 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | orgmode for Sublime Text 2 & 3 2 | ============= 3 | 4 | Adds support for [Org mode](http://orgmode.org)'s [.org syntax](http://orgmode.org/worg/dev/org-syntax.html) files to Sublime Text. 5 | 6 | Tested **on Windows 7 and Ubuntu 12.04 and Mac OS X 10.7.5** with Sublime Text 2 & 3 7 | 8 | 9 | Features 10 | ============= 11 | 12 | _Full feature list available in [install.org](messages/install.org#features) or via the Sublime Text menus at Package Settings -> orgmode -> Readme.org_ 13 | 14 | ![Features](https://raw.github.com/danielmagnussons/orgmode/master/images/screenshot1.png) 15 | 16 | 17 | Todo 18 | ============= 19 | _Full todo list available in [install.org](https://github.com/danielmagnussons/orgmode/blob/master/messages/install.org) or via the Sublime Text menus at Package Settings -> orgmode -> Readme.org_ 20 | ![Todo](https://raw.github.com/danielmagnussons/orgmode/master/images/screenshot2.png) 21 | More Todo in Sublime Text 2/Packages/README.org 22 | 23 | 24 | Install with Package Control 25 | ============= 26 | 27 | Package Control : Install Package 28 | Search for "orgmode" 29 | Restart Sublime 30 | 31 | 32 | Manual install 33 | ============= 34 | 35 | cd .../Sublime Text 2/Packages/ 36 | git clone git@github.com:danielmagnussons/orgmode.git 37 | restart sublime 38 | open .../Sublime Text 2/Packages/README.org 39 | 40 | 41 | Other 42 | ============= 43 | 44 | * Forked from https://bitbucket.org/theblacklion/sublime_orgmode/ 45 | * Inspired by http://orgmode.org/ 46 | -------------------------------------------------------------------------------- /Symbol List.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol List 7 | scope 8 | text.orgmode orgmode.page, text.orgmode orgmode.break, text.orgmode orgmode.headline 9 | settings 10 | 11 | showInSymbolList 12 | 1 13 | symbolTransformation 14 | 15 | s/\s*\**\s*\z//g; #Search for * 16 | s/(?<=\*)\*/ /g; #replace * with two spaces, except first 17 | s/^\*( *)\s+(.*)/$1$2/; #replace first found with a space 18 | 19 | 20 | uuid 21 | 7A121D96-5F22-41B1-B749-8C4FCA7EA592 22 | 23 | 24 | -------------------------------------------------------------------------------- /help_it.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Integrated from http://www.sublimetext.com/forum/viewtopic.php?f=5&t=2674 3 | Plugin inspired and modified from http://www.sublimetext.com/forum/viewtopic.php?f=5&t=2242 4 | 5 | keys; 6 | { "keys": ["alt+f1"], "command": "help_it" } 7 | ''' 8 | import sublime 9 | import sublime_plugin 10 | import webbrowser 11 | import re 12 | 13 | 14 | class helpItCommand(sublime_plugin.TextCommand): 15 | 16 | """ 17 | This will search a word in a language's documenation or google it with it's scope otherwise 18 | """ 19 | 20 | def run(self, edit): 21 | if len(self.view.file_name()) > 0: 22 | settings = sublime.load_settings('orgmode.sublime-settings') 23 | item = None 24 | word = self.view.substr(self.view.word(self.view.sel()[0].begin())) 25 | scope = self.view.scope_name(self.view.sel()[0].begin()).strip() 26 | getlang = scope.split('.') 27 | language = getlang[-1] 28 | if language == 'basic': 29 | language = getlang[-2] 30 | 31 | if language == 'html': # HTML shows up A LOT for internal CSS, PHP and JS 32 | if 'php' in getlang: 33 | language = 'php' 34 | elif 'js' in getlang: 35 | language = 'js' 36 | elif 'css' in getlang: 37 | language = 'css' 38 | 39 | # Map languages if needed. For example: Map .less files to .css 40 | # searches 41 | print('language: ' + language) 42 | if settings.get(language) is not None: 43 | print('lang found in settings: ' + language) 44 | item = settings.get(language) 45 | if 'map' in item: 46 | language = item['map'] 47 | 48 | sublime.status_message( 49 | 'helpIt invoked-- ' + 'Scope: ' + scope + ' Word: ' + word + ' Language: ' + language) 50 | for region in self.view.sel(): 51 | phrase = self.view.substr(region) 52 | search = 'http://google.com/search?q=%s' 53 | custom = False 54 | 55 | # Define our search term 56 | if not region.empty(): 57 | term = phrase 58 | else: 59 | term = word 60 | 61 | if item != None: 62 | if 'sub' in item: # check for sub searches based on our term 63 | subs = item['sub'] 64 | for sub in subs: 65 | if 'contains' in sub and 'url' in sub: # Make sure we have everything 66 | if term.count(sub['contains']): 67 | if 'remove' in sub: 68 | term = re.sub(sub['remove'], '', term) 69 | search = sub['url'] 70 | custom = True 71 | break 72 | 73 | if not custom: 74 | if isinstance(item, str): 75 | search = item 76 | custom = True 77 | elif 'url' in item: 78 | search = item['url'] 79 | custom = True 80 | 81 | if not custom: 82 | term += " " + language 83 | 84 | try: 85 | search = search % (term) 86 | print(search) 87 | except TypeError: 88 | print("No replacements") 89 | 90 | webbrowser.open_new_tab(search) 91 | else: 92 | pass 93 | 94 | def is_enabled(self): 95 | return self.view.file_name() and len(self.view.file_name()) > 0 96 | -------------------------------------------------------------------------------- /images/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielmagnussons/orgmode/73d52ba15a39e0c0649ed268ca1f268800a990aa/images/screenshot1.png -------------------------------------------------------------------------------- /images/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielmagnussons/orgmode/73d52ba15a39e0c0649ed268ca1f268800a990aa/images/screenshot2.png -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.org", 3 | "1.7.0": "messages/1.7.0.org", 4 | "1.7.4": "messages/1.7.4.org" 5 | } 6 | -------------------------------------------------------------------------------- /messages/1.7.0.org: -------------------------------------------------------------------------------- 1 | 2 | [X] updated to 1.7.0 -------------------------------------------------------------------------------- /messages/1.7.4.org: -------------------------------------------------------------------------------- 1 | 2 | * What's new 3 | - When tabbing on a headline, like this on 'What's new' it will be folded. Tab on it again to unfold. 4 | - Everything folded/unfolded will be saved. 5 | - Sublime has a few fold keys built in, search for 'fold' in Default.sublime.keymap -------------------------------------------------------------------------------- /messages/1.7.8.org: -------------------------------------------------------------------------------- 1 | 2 | * What's new 3 | - Summary of checkboxes will work better when nesting them like below 4 | - Fixes: [[https://github.com/danielmagnussons/orgmode/issues/34]] 5 | 6 | --- 7 | 8 | * Headline with summary [2/3] 9 | - [X] Do this 10 | - [X] Then this 11 | - [ ] Do this big task [0/2] 12 | - [ ] With a lot of sub tasks 13 | - [ ] And check the summary checkboxes. 14 | 15 | * Second headline here with more tasks [1/2] 16 | - [ ] One 17 | - [X] Two -------------------------------------------------------------------------------- /messages/1.9.0.org: -------------------------------------------------------------------------------- 1 | 2 | * What's new 3 | 4 | 0269d47 Save folding with filename instead of view_index 5 | d3021e7 Remove spammy print 6 | fa487b1 Use realpath(__file__) instead of packages_path() 7 | 7c78a6f (martisak-todo) Merge branch 'todo' of github.com:martisak/orgmode into todo 8 | 36ee5a3 Hack to avoid problems if cursor is at the end of the line 9 | a37d433 Added example in install.org 10 | 2f8f5ae Merge pull request #69 from kxtcd950/master 11 | 4ae2b23 Added todo cycle to default keymaps 12 | 25d4817 Removed a print statement 13 | bf5f7b4 Pressing enter on TODO now changes to WORKING, and then DONE 14 | 514814a Added tri-state checkboxes. Some API changes as a result, but now a checkbox list performs identically to Emacs' orgmode checkboxes. 15 | ab2b1c0 Merge pull request #55 from edbedbe/master 16 | f5f3a56 added light org-mode color theme 17 | 9d22c59 Merge pull request #48 from rbenson/patch-1 18 | 34b9438 Merge pull request #47 from rbenson/master 19 | c158dde Update install.org 20 | a727cae adds support for deadlines and scheduled 21 | 1a1559c Merge pull request #46 from rbenson/master 22 | 4b9b94a Added support for headlines in GoTo Symbol 23 | -------------------------------------------------------------------------------- /messages/install.org: -------------------------------------------------------------------------------- 1 | * After Install 2 | Apply orgmode syntax, ctrl+shift+p , then search for orgmode. This document will be colored. 3 | 4 | * Features 5 | Here's a list of all the features implemented so far: 6 | 7 | * Context sensitive highlighting 8 | - Headlines 9 | - Deadlines and due dates 10 | - Pages. E.g.: 11 | --- This is a page marker --- 12 | - Breaks. E.g.: 13 | ~ This is a break. 14 | - Tasks 15 | - Tags. E.g.: :important:, :one:two:three: 16 | - Follow ups. E.g.: 17 | -> Lorem ipsum. 18 | => Lorem ipsum. 19 | - Checkboxes 20 | - Checkbox summaries 21 | - External links 22 | - Inter document links. E.g. {1} {{Context sensitive actions}} {{Todo}} 23 | - Code blocks 24 | - Python tracebacks 25 | 26 | * Context sensitive actions 27 | - Toggle checkbox on pressing enter 28 | - TODO chain status cycles on pressing enter 29 | - Auto update of checkbox summary on toggle of checkboxes 30 | - Recalc number of children in checkbox summary on pressing enter 31 | - External link opener on pressing enter 32 | (currently only working on OSX and Windows) 33 | - Plugin-system including aliases 34 | - Plugin: Jira 35 | - Normal call: [[jira:PLAYGROUND]] 36 | - Alias j: [[j:PLAYGROUND-123]] 37 | - Plugin: Crucible code review 38 | - Normal call: [[crucible:CR-123]] 39 | - Aliases cru and cr: [[cr:CR-123]] 40 | - Plugin: FishEye repo incl. opt. changeset 41 | - Normal call: [[fisheye:some_repo]] 42 | - Normal call: [[fisheye:some_repo/revision_or_tag]] 43 | - Aliases fish and fe: [[fe:some_repo/123]] 44 | - Plugin: eMail 45 | - Create call: [[mailto:ok@ryotic.de]] 46 | - Create call with subject: [[mailto:ok@ryotic.de/some subject]] 47 | - Auto completion of filenames and directories when writing external links to local files 48 | - Jump between inter document links on pressing enter (e.g. {1}) 49 | - Jump to linked headline on pressing enter (e.g. {{Installation}}) 50 | - Show an outline of the document on using goto symbol 51 | - Open Python file at specific line from Python tracebacks when pressing enter on a filepath 52 | 53 | * Tab completions 54 | - Headlines: "*", "**", "***" 55 | - Pages: "p" 56 | - Breaks: "b" 57 | - Task: "-" 58 | - Task with unchecked checkbox: "-c" 59 | - Task with checked checkbox: "-cc" 60 | - Task with unchecked checkbox and external link: "-cl" 61 | - Task with TODO: "-t" 62 | - Task with WORKING: "-w" 63 | - Task with DONE: "-d" 64 | - Tag: "t" 65 | - Additional Tags: ":" (just keep hitting tab for more) 66 | - Follow ups: "f" 67 | - Sum ups: "ff" 68 | - External links: "l" 69 | - Inter document links: "i", "ii" 70 | - Checkbox unchecked: "c" 71 | - Checkbox checked: "cc" 72 | - Checkbox summary: "cs" 73 | 74 | * Todo [15/31] 75 | - [X] Persistant folding of headlines 76 | - needs indented formatting to work. 77 | - [X] Autocomplete for inserting current date, write "date" => 2013-05-25 18:53 78 | - [X] configure in settings 79 | - [X] Port to Sublime Text 3 80 | - [X] test 81 | - [X] mac, 82 | - [X] win, 83 | - [X] linux 84 | - [X] merge into sub2 branch, test both versions 85 | - [X] [[mailto:daniel@testtest.se]] 86 | - [X] support [[http://github.com]], [[https://github.com]] 87 | - [X] support [[cmd:c:\dev]] 88 | - [X] test all resolvers 89 | - [X] make key triggers work 90 | - [X] make theme work 91 | - [X] tmLangugage not working 92 | - [X] not crash on start 93 | - [X] import modules py3.3 style 94 | - [X] HelpIt integrated, alt+f1 looks up th eword on google. 95 | - [X] redmine, [[redmine:9726]], [[issue:9726]], [[#9726]] 96 | - [X] local file not working well for windows 97 | - [X] åäö problems 98 | - [X] linux open cmd line at "[[cmd:/home]]" 99 | - [X] open cmd line at "[[cmd:c:\dev]]" 100 | - [[cmd:c:\dev\]] 101 | - [[prompt:c:\dev\apps]] 102 | - [X] http resolver, make urls with '#'' work 103 | - [[http://www.sublimetext.com/forum/viewtopic.php?f=5&t=1838&p=18483#p18483]] 104 | - [X] https is not working, [[https://www.google.com/]] 105 | -https resolver.. 106 | - [X] navigation history 107 | - [X] src refactor, moved settings to Global.sublime-settings 108 | - [X] added default theme in orgmode dir. 109 | - [X] External link opener on pressing enter [3/3] 110 | - [X] on OSX 111 | - [X] on Linux 112 | - [X] on Windows 113 | - [X] When (un-)checking *all* checkboxes of siblings, toggle parent checkbox. 114 | - [ ] Either make highlight_code_remarks.py configurable thru view settings so that orgmode can control its regex patterns or fork/extend it to archive an equal goal. 115 | - [ ] Export into formatted text file [0/1] 116 | - [ ] Format: Markdown 117 | - [ ] Automatic export after save into given format if mark found in org file. 118 | - [ ] Fix cursor position after filling checkbox summary on checkbox toggle 119 | - [ ] Tab trigger "c" [1/2] 120 | - [X] …which extends into "[ ] " 121 | - [ ] …and updates the summary 122 | - [ ] Define special block/area in document where time logging can occur. If one changes the status (TODO, WORKING, DONE etc.) this will be written into the log. Ideas for format are welcome! 123 | - [ ] If all children don't have checkboxes only show the number of children in the summary 124 | - [ ] If the summary ends with "%]" calculate percentage instead of amount 125 | - [ ] If multiple checkboxes are in one line only work with the one under the cursor 126 | - [ ] If multiple checkbox summaries are in one line only work with the one under the cursor 127 | - [ ] If mutliple checkbox summaries are in one line update every one of them independently on updating a child checkbox 128 | - [ ] Move key bindings out of readme into its own file 129 | - [ ] Move theme additions out of readme into its own file 130 | - [ ] Implement external link plugin: eMail [2/3] 131 | - [ ] Open call [[email:ok@ryotic.de/inbox/some title]] 132 | - [X] Create call [[mailto:ok@ryotic.de]] 133 | - [X] Create call with subject [[mailto:ok@ryotic.de/some subject]] 134 | - [X] Pressing return on a TODO chain shall set it to DONE 135 | - [ ] ASCII tables. 136 | - [ ] Code remark collector. Recursively scans a specified folder for files with given filename pattern for code remarks and shows them as a list. Should be realized with begin and end markers to support later update on pressing enter on either marker. 137 | 138 | 139 | * Known Issues 140 | - Subsequent indent of wrapped paragraphs don't respect stars, tacks, checkboxes, follow ups etc.. 141 | -> [[http://sublimetext.userecho.com/feedback/26943-/]] 142 | - Update of checkbox summary should only see children who start with either an asterisk, tack or checkbox. Other things like external links or follow ups should be ignored. 143 | 144 | * External links 145 | {1} Homepage [[https://github.com/danielmagnussons/orgmode]] 146 | {2} Issue tracker [[https://github.com/danielmagnussons/orgmode/issues?state=open]] 147 | {3} Sublime Text 2 [[http://www.sublimetext.com/2]] 148 | {4} Org-Mode for Emacs [[http://orgmode.org/]] 149 | 150 | * Optional Attachments 151 | 152 | * Theme additions for proper syntax highlighting 153 | If you are not using Monokai Bright.tmTheme, put the following into your color scheme (.tmTheme file): 154 | 155 | [code] 156 | 157 | name 158 | orgmode link 159 | scope 160 | orgmode.link 161 | settings 162 | 163 | foreground 164 | #FB9A4B 165 | fontStyle 166 | underline 167 | 168 | 169 | 170 | name 171 | orgmode page 172 | scope 173 | orgmode.page 174 | settings 175 | 176 | foreground 177 | #FFFFAA 178 | 179 | 180 | 181 | name 182 | orgmode break 183 | scope 184 | orgmode.break 185 | settings 186 | 187 | foreground 188 | #FFAAAA 189 | 190 | 191 | 192 | name 193 | orgmode headline 194 | scope 195 | orgmode.headline 196 | settings 197 | 198 | foreground 199 | #9EFFFF 200 | 201 | 202 | 203 | name 204 | orgmode tack 205 | scope 206 | orgmode.tack 207 | settings 208 | 209 | foreground 210 | #FFFFAA 211 | 212 | 213 | 214 | name 215 | orgmode follow up 216 | scope 217 | orgmode.follow_up 218 | settings 219 | 220 | foreground 221 | #FFFFAA 222 | 223 | 224 | 225 | name 226 | orgmode checkbox 227 | scope 228 | orgmode.checkbox 229 | settings 230 | 231 | foreground 232 | #FFFFAA 233 | 234 | 235 | 236 | name 237 | orgmode checkbox summary 238 | scope 239 | orgmode.checkbox.summary 240 | settings 241 | 242 | foreground 243 | #FFFFAA 244 | 245 | 246 | 247 | name 248 | orgmode tags 249 | scope 250 | orgmode.tags 251 | settings 252 | 253 | foreground 254 | #AAFFAA 255 | 256 | 257 | 258 | 259 | name 260 | orgmode deadline 261 | scope 262 | orgmode.deadline 263 | settings 264 | 265 | foreground 266 | #AAFFAA 267 | 268 | 269 | 270 | name 271 | orgmode scheduled 272 | scope 273 | orgmode.scheduled 274 | settings 275 | 276 | foreground 277 | #0099FF 278 | 279 | 280 | 281 | [/code] 282 | -------------------------------------------------------------------------------- /navigation_history.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | http://www.sublimetext.com/forum/viewtopic.php?f=5&t=2738 4 | 5 | https://github.com/optilude/SublimeTextMisc 6 | 7 | 8 | Put this in your "Packages" directory and then configure "Key bindings - User" to use it. I use these keybindings for it on OS X: 9 | 10 | { "keys": ["alt+left"], "command": "navigation_history_back"}, 11 | { "keys": ["alt+right"], "command": "navigation_history_forward"} 12 | 13 | ''' 14 | 15 | 16 | import sublime 17 | import sublime_plugin 18 | from collections import deque 19 | 20 | MAX_SIZE = 64 21 | LINE_THRESHOLD = 2 22 | 23 | 24 | class Location(object): 25 | 26 | """A location in the history 27 | """ 28 | def __init__(self, path, line, col): 29 | self.path = path 30 | self.line = line 31 | self.col = col 32 | 33 | def __eq__(self, other): 34 | return self.path == other.path and self.line == other.line 35 | 36 | def __ne__(self, other): 37 | return not self.__eq__(other) 38 | 39 | def __bool__(self): 40 | return (self.path is not None and self.line is not None) 41 | 42 | def near(self, other): 43 | return self.path == other.path and abs(self.line - other.line) <= LINE_THRESHOLD 44 | 45 | def copy(self): 46 | return Location(self.path, self.line, self.col) 47 | 48 | 49 | class History(object): 50 | 51 | """Keep track of the history for a single window 52 | """ 53 | 54 | def __init__(self, max_size=MAX_SIZE): 55 | self._current = None # current location as far as the 56 | # history is concerned 57 | self._back = deque([], max_size) # items before self._current 58 | self._forward = deque([], max_size) # items after self._current 59 | 60 | self._last_movement = None # last recorded movement 61 | 62 | def record_movement(self, location): 63 | """Record movement to the given location, pushing history if 64 | applicable 65 | """ 66 | 67 | if location: 68 | if self.has_changed(location): 69 | self.push(location) 70 | self.mark_location(location) 71 | 72 | def mark_location(self, location): 73 | """Remember the current location, for the purposes of being able 74 | to do a has_changed() check. 75 | """ 76 | self._last_movement = location.copy() 77 | 78 | def has_changed(self, location): 79 | """Determine if the given location combination represents a 80 | significant enough change to warrant pushing history. 81 | """ 82 | 83 | return self._last_movement is None or not self._last_movement.near(location) 84 | 85 | def push(self, location): 86 | """Push the given location to the back history. Clear the forward 87 | history. 88 | """ 89 | 90 | if self._current is not None: 91 | self._back.append(self._current.copy()) 92 | self._current = location.copy() 93 | self._forward.clear() 94 | 95 | def back(self): 96 | """Move backward in history, returning the location to jump to. 97 | Returns None if no history. 98 | """ 99 | 100 | if not self._back: 101 | return None 102 | 103 | self._forward.appendleft(self._current) 104 | self._current = self._back.pop() 105 | self._last_movement = self._current # preempt, so we don't re-push 106 | return self._current 107 | 108 | def forward(self): 109 | """Move forward in history, returning the location to jump to. 110 | Returns None if no history. 111 | """ 112 | 113 | if not self._forward: 114 | return None 115 | 116 | self._back.append(self._current) 117 | self._current = self._forward.popleft() 118 | self._last_movement = self._current # preempt, so we don't re-push 119 | return self._current 120 | 121 | _histories = {} # window id -> History 122 | 123 | 124 | def get_history(): 125 | """Get a History object for the current window, 126 | creating a new one if required 127 | """ 128 | 129 | window = sublime.active_window() 130 | if window is None: 131 | return None 132 | 133 | window_id = window.id() 134 | history = _histories.get(window_id, None) 135 | if history is None: 136 | _histories[window_id] = history = History() 137 | return history 138 | 139 | 140 | class NavigationHistoryRecorder(sublime_plugin.EventListener): 141 | 142 | """Keep track of history 143 | """ 144 | 145 | def on_selection_modified(self, view): 146 | """When the selection is changed, possibly record movement in the 147 | history 148 | """ 149 | history = get_history() 150 | if history is None: 151 | return 152 | 153 | path = view.file_name() 154 | row, col = view.rowcol(view.sel()[0].a) 155 | history.record_movement(Location(path, row + 1, col + 1)) 156 | 157 | # def on_close(self, view): 158 | # """When a view is closed, check to see if the window was closed too 159 | # and clean up orphan histories 160 | # """ 161 | # 162 | # XXX: This doesn't work - event runs before window is removed 163 | # from sublime.windows() 164 | # 165 | # windows_with_history = set(_histories.keys()) 166 | # window_ids = set([w.id() for w in sublime.windows()]) 167 | # closed_windows = windows_with_history.difference(window_ids) 168 | # for window_id in closed_windows: 169 | # del _histories[window_id] 170 | 171 | 172 | class NavigationHistoryBack(sublime_plugin.TextCommand): 173 | 174 | """Go back in history 175 | """ 176 | 177 | def run(self, edit): 178 | history = get_history() 179 | if history is None: 180 | return 181 | 182 | location = history.back() 183 | if location: 184 | window = sublime.active_window() 185 | window.open_file("%s:%d:%d" % ( 186 | location.path, location.line, location.col), sublime.ENCODED_POSITION) 187 | 188 | 189 | class NavigationHistoryForward(sublime_plugin.TextCommand): 190 | 191 | """Go forward in history 192 | """ 193 | 194 | def run(self, edit): 195 | history = get_history() 196 | if history is None: 197 | return 198 | 199 | location = history.forward() 200 | if location: 201 | window = sublime.active_window() 202 | window.open_file("%s:%d:%d" % ( 203 | location.path, location.line, location.col), sublime.ENCODED_POSITION) 204 | -------------------------------------------------------------------------------- /orgmode.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Settings in orgmode.sublime-settings are: 3 | - orgmode.open_link.resolvers: See DEFAULT_OPEN_LINK_RESOLVERS. 4 | - orgmode.open_link.resolver.abstract.commands: See DEFAULT_OPEN_LINK_COMMANDS in resolver.abstract. 5 | For more settings see headers of specific resolvers. 6 | ''' 7 | 8 | import sys 9 | import re 10 | import os.path 11 | import sublime 12 | import sublime_plugin 13 | import fnmatch 14 | import datetime 15 | 16 | 17 | try: 18 | import importlib 19 | except ImportError: 20 | pass 21 | 22 | 23 | DEFAULT_OPEN_LINK_RESOLVERS = [ 24 | 'http', 25 | 'https', 26 | 'prompt', 27 | 'redmine', 28 | 'jira', 29 | 'crucible', 30 | 'fisheye', 31 | 'email', 32 | 'local_file', 33 | ] 34 | 35 | 36 | class OrgmodeNewTaskDocCommand(sublime_plugin.WindowCommand): 37 | 38 | def run(self): 39 | view = self.window.new_file() 40 | view.set_syntax_file('Packages/orgmode/orgmode.tmLanguage') 41 | 42 | 43 | def find_resolvers(): 44 | base = os.path.dirname(os.path.abspath(__file__)) 45 | path = base + '/resolver' 46 | available_resolvers = {} 47 | for root, dirnames, filenames in os.walk(base + '/resolver'): 48 | for filename in fnmatch.filter(filenames, '*.py'): 49 | module_path = 'orgmode.resolver.' + filename.split('.')[0] 50 | if sys.version_info[0] < 3: 51 | module_path = 'resolver.' + filename.split('.')[0] 52 | name = filename.split('.')[0] 53 | module = __import__(module_path, globals(), locals(), name) 54 | module = reload(module) 55 | else: 56 | module = importlib.import_module(module_path) 57 | if '__init__' in filename or 'abstract' in filename: 58 | continue 59 | available_resolvers[filename.split('.')[0]] = module 60 | return available_resolvers 61 | available_resolvers = find_resolvers() 62 | 63 | 64 | class OrgmodeOpenLinkCommand(sublime_plugin.TextCommand): 65 | 66 | def __init__(self, *args, **kwargs): 67 | super(OrgmodeOpenLinkCommand, self).__init__(*args, **kwargs) 68 | settings = sublime.load_settings('orgmode.sublime-settings') 69 | wanted_resolvers = settings.get( 70 | 'orgmode.open_link.resolvers', DEFAULT_OPEN_LINK_RESOLVERS) 71 | self.resolvers = [available_resolvers[name].Resolver(self.view) 72 | for name in wanted_resolvers] 73 | 74 | def resolve(self, content): 75 | for resolver in self.resolvers: 76 | result = resolver.resolve(content) 77 | if result is not None: 78 | return resolver, result 79 | return None, None 80 | 81 | def is_valid_scope(self, sel): 82 | scope_name = self.view.scope_name(sel.end()) 83 | return 'orgmode.link' in scope_name 84 | 85 | def extract_content(self, region): 86 | content = self.view.substr(region) 87 | if content.startswith('[[') and content.endswith(']]'): 88 | content = content[2:-2] 89 | return content 90 | 91 | def run(self, edit): 92 | view = self.view 93 | for sel in view.sel(): 94 | if not self.is_valid_scope(sel): 95 | continue 96 | region = view.extract_scope(sel.end()) 97 | content = self.extract_content(region) 98 | resolver, content = self.resolve(content) 99 | if content is None: 100 | sublime.error_message('Could not resolve link:\n%s' % content) 101 | continue 102 | resolver.execute(content) 103 | 104 | 105 | class OrgmodeOpenPythonRefCommand(OrgmodeOpenLinkCommand): 106 | 107 | def __init__(self, *args, **kwargs): 108 | super(OrgmodeOpenPythonRefCommand, self).__init__(*args, **kwargs) 109 | pattern = r'.+", line (?P\d+), in (?P.+)$' 110 | self.regex = re.compile(pattern) 111 | 112 | def is_valid_scope(self, sel): 113 | scope_name = self.view.scope_name(sel.end()) 114 | return 'filepath reference orgmode.python.traceback' in scope_name 115 | 116 | def extract_content(self, region): 117 | content = self.view.substr(region) 118 | outer_region = self.view.extract_scope(region.end() + 1) 119 | scope_name = self.view.scope_name(region.end() + 1) 120 | # print scope_name 121 | if 'reference orgmode.python.traceback' in scope_name: 122 | outer_content = self.view.substr(outer_region) 123 | # print outer_content 124 | match = self.regex.match(outer_content) 125 | if match: 126 | # print match.groupdict() 127 | content += ':%s' % match.group('line') 128 | return content 129 | 130 | 131 | class OrgmodeCycleInternalLinkCommand(sublime_plugin.TextCommand): 132 | 133 | def run(self, edit): 134 | view = self.view 135 | sels = view.sel() 136 | sel = sels[0] 137 | if 'orgmode.link.internal' not in view.scope_name(sel.end()): 138 | return 139 | region = view.extract_scope(sel.end()) 140 | content = view.substr(region).strip() 141 | if content.startswith('{{') and content.endswith('}}'): 142 | content = '* %s' % content[2:-2] 143 | found = self.view.find(content, region.end(), sublime.LITERAL) 144 | if not found: # Try wrapping around buffer. 145 | found = self.view.find(content, 0, sublime.LITERAL) 146 | same = region.a == found.a and region.b == found.b 147 | if not found or same: 148 | sublime.status_message('No sibling found for: %s' % content) 149 | return 150 | found = view.extract_scope(found.begin()) 151 | sels.clear() 152 | sels.add(sublime.Region(found.begin())) 153 | try: 154 | import show_at_center_and_blink 155 | view.run_command('show_at_center_and_blink') 156 | except ImportError: 157 | view.show_at_center(found) 158 | 159 | class CheckState: 160 | Unchecked, Checked, Indeterminate, Error = range(1, 5); 161 | 162 | 163 | class AbstractCheckboxCommand(sublime_plugin.TextCommand): 164 | 165 | def __init__(self, *args, **kwargs): 166 | super(AbstractCheckboxCommand, self).__init__(*args, **kwargs) 167 | indent_pattern = r'^(\s*).*$' 168 | summary_pattern = r'(\[\d*[/]\d*\])' 169 | checkbox_pattern = r'(\[[X\- ]\])' 170 | self.indent_regex = re.compile(indent_pattern) 171 | self.summary_regex = re.compile(summary_pattern) 172 | self.checkbox_regex = re.compile(checkbox_pattern) 173 | 174 | def get_indent(self, content): 175 | if isinstance(content, sublime.Region): 176 | content = self.view.substr(content) 177 | match = self.indent_regex.match(content) 178 | indent = match.group(1) 179 | return indent 180 | 181 | def find_parent(self, region): 182 | view = self.view 183 | row, col = view.rowcol(region.begin()) 184 | line = view.line(region) 185 | content = view.substr(line) 186 | # print content 187 | indent = len(self.get_indent(content)) 188 | # print repr(indent) 189 | row -= 1 190 | found = False 191 | while row >= 0: 192 | point = view.text_point(row, 0) 193 | line = view.line(point) 194 | content = view.substr(line) 195 | if len(content.strip()): 196 | cur_indent = len(self.get_indent(content)) 197 | if cur_indent < indent: 198 | found = True 199 | break 200 | row -= 1 201 | if found: 202 | # print row 203 | point = view.text_point(row, 0) 204 | line = view.line(point) 205 | return line 206 | 207 | def find_children(self, region): 208 | view = self.view 209 | row, col = view.rowcol(region.begin()) 210 | line = view.line(region) 211 | content = view.substr(line) 212 | # print content 213 | indent = len(self.get_indent(content)) 214 | # print repr(indent) 215 | row += 1 216 | child_indent = None 217 | children = [] 218 | last_row, _ = view.rowcol(view.size()) 219 | while row <= last_row: 220 | point = view.text_point(row, 0) 221 | line = view.line(point) 222 | content = view.substr(line) 223 | summary = self.get_summary(line) 224 | if summary and content.lstrip().startswith("*"): 225 | break 226 | if self.checkbox_regex.search(content): 227 | cur_indent = len(self.get_indent(content)) 228 | # check for end of descendants 229 | if cur_indent <= indent: 230 | break 231 | # only immediate children 232 | if child_indent is None: 233 | child_indent = cur_indent 234 | if cur_indent == child_indent: 235 | children.append(line) 236 | row += 1 237 | return children 238 | 239 | def find_siblings(self, child, parent): 240 | view = self.view 241 | row, col = view.rowcol(parent.begin()) 242 | parent_indent = self.get_indent(parent) 243 | child_indent = self.get_indent(child) 244 | # print '***', repr(parent_indent), repr(child_indent) 245 | siblings = [] 246 | row += 1 247 | last_row, _ = view.rowcol(view.size()) 248 | while row <= last_row: # Don't go past end of document. 249 | line = view.text_point(row, 0) 250 | line = view.line(line) 251 | content = view.substr(line) 252 | # print content 253 | if len(content.strip()): 254 | cur_indent = self.get_indent(content) 255 | if len(cur_indent) <= len(parent_indent): 256 | # print 'OUT' 257 | break # Indent same as parent found! 258 | if len(cur_indent) == len(child_indent): 259 | # print 'MATCH' 260 | siblings.append((line, content)) 261 | row += 1 262 | return siblings 263 | 264 | def get_summary(self, line): 265 | view = self.view 266 | row, _ = view.rowcol(line.begin()) 267 | content = view.substr(line) 268 | # print content 269 | match = self.summary_regex.search(content) 270 | if not match: 271 | return None 272 | # summary = match.group(1) 273 | # print(repr(summary)) 274 | # print dir(match), match.start(), match.span() 275 | col_start, col_stop = match.span() 276 | return sublime.Region( 277 | view.text_point(row, col_start), 278 | view.text_point(row, col_stop), 279 | ) 280 | 281 | def get_checkbox(self, line): 282 | view = self.view 283 | row, _ = view.rowcol(line.begin()) 284 | content = view.substr(line) 285 | # print content 286 | match = self.checkbox_regex.search(content) 287 | if not match: 288 | return None 289 | # checkbox = match.group(1) 290 | # print repr(checkbox) 291 | # print dir(match), match.start(), match.span() 292 | col_start, col_stop = match.span() 293 | return sublime.Region( 294 | view.text_point(row, col_start), 295 | view.text_point(row, col_stop), 296 | ) 297 | 298 | def get_check_state(self, line): 299 | if '[-]' in self.view.substr(line): 300 | return CheckState.Indeterminate 301 | if '[ ]' in self.view.substr(line): 302 | return CheckState.Unchecked 303 | if '[X]' in self.view.substr(line): 304 | return CheckState.Checked 305 | return CheckState.Error 306 | 307 | def get_check_char(self, check_state): 308 | if check_state == CheckState.Unchecked: 309 | return ' ' 310 | elif check_state == CheckState.Checked: 311 | return 'X' 312 | elif check_state == CheckState.Indeterminate: 313 | return '-' 314 | else: 315 | return 'E' 316 | 317 | def recalc_summary(self, region): 318 | # print('recalc_summary') 319 | children = self.find_children(region) 320 | if not len(children) > 0: 321 | return (0, 0) 322 | # print children 323 | num_children = len(children) 324 | checked_children = len( 325 | [child for child in children if (self.get_check_state(child) == CheckState.Checked)]) 326 | # print ('checked_children: ' + str(checked_children) + ', num_children: ' + str(num_children)) 327 | return (num_children, checked_children) 328 | 329 | def update_line(self, edit, region, parent_update=True): 330 | #print ('update_line', self.view.rowcol(region.begin())[0]+1) 331 | (num_children, checked_children) = self.recalc_summary(region) 332 | if not num_children > 0: 333 | return False 334 | # update region checkbox 335 | if checked_children == num_children: 336 | newstate = CheckState.Checked 337 | else: 338 | if checked_children != 0: 339 | newstate = CheckState.Indeterminate 340 | else: 341 | newstate = CheckState.Unchecked 342 | self.toggle_checkbox(edit, region, newstate) 343 | # update region summary 344 | self.update_summary(edit, region, checked_children, num_children) 345 | 346 | children = self.find_children(region) 347 | for child in children: 348 | line = self.view.line(child) 349 | summary = self.get_summary(self.view.line(child)) 350 | if summary: 351 | return self.update_line(edit, line, parent_update=False) 352 | 353 | if parent_update: 354 | parent = self.find_parent(region) 355 | if parent: 356 | self.update_line(edit, parent) 357 | 358 | return True 359 | 360 | def update_summary(self, edit, region, checked_children, num_children): 361 | # print('update_summary', self.view.rowcol(region.begin())[0]+1) 362 | view = self.view 363 | summary = self.get_summary(region) 364 | if not summary: 365 | return False 366 | # print('checked_children: ' + str(checked_children) + ', num_children: ' + str(num_children)) 367 | view.replace(edit, summary, '[%d/%d]' % ( 368 | checked_children, num_children)) 369 | 370 | def toggle_checkbox(self, edit, region, checked=None, recurse_up=False, recurse_down=False): 371 | # print 'toggle_checkbox', self.view.rowcol(region.begin())[0]+1 372 | view = self.view 373 | checkbox = self.get_checkbox(region) 374 | if not checkbox: 375 | return False 376 | if checked is None: 377 | check_state = self.get_check_state(region) 378 | if (check_state == CheckState.Unchecked) | (check_state == CheckState.Indeterminate): 379 | check_state = CheckState.Checked 380 | elif (check_state == CheckState.Checked): 381 | check_state = CheckState.Unchecked 382 | else: 383 | check_state = checked 384 | view.replace(edit, checkbox, '[%s]' % ( self.get_check_char(check_state))) 385 | if recurse_down: 386 | # all children should follow 387 | children = self.find_children(region) 388 | for child in children: 389 | self.toggle_checkbox(edit, child, check_state, recurse_down=True) 390 | if recurse_up: 391 | # update parent 392 | parent = self.find_parent(region) 393 | if parent: 394 | self.update_line(edit, parent) 395 | 396 | 397 | class OrgmodeCycleTodoCommand(sublime_plugin.TextCommand): 398 | 399 | def __init__(self, *args, **kwargs): 400 | super(OrgmodeCycleTodoCommand, self).__init__(*args, **kwargs) 401 | 402 | self.status = ["TODO", "WORKING", "DONE"] 403 | todo_pattern = r"|".join(self.status) 404 | self.todo_regex = re.compile(todo_pattern) 405 | 406 | 407 | def run(self, edit): 408 | 409 | view = self.view 410 | sels = view.sel() 411 | sel = sels[0] 412 | 413 | # Get the scope name for the current cursor position 414 | # also contains other scopes 415 | if 'orgmode.todo' not in view.scope_name(sel.end()): 416 | return 417 | 418 | # If the cursor is at the end of the view, return. 419 | if (sel.end() == sel.begin()) and (sel.end() == view.size()): 420 | view.insert(edit, view.size(), "\n") 421 | view.show(view.size()) 422 | return 423 | 424 | region = view.extract_scope(sel.end()) 425 | 426 | todo = self.get_todo(region) 427 | content = self.view.substr(todo) 428 | 429 | next_status_index = (self.status.index(content) + 1) % len(self.status) 430 | view.replace(edit, todo, self.status[next_status_index]) 431 | 432 | 433 | def get_todo(self, line): 434 | view = self.view 435 | row, _ = view.rowcol(line.begin()) 436 | content = view.substr(line) 437 | # print content 438 | match = self.todo_regex.search(content) 439 | if not match: 440 | return None 441 | # checkbox = match.group(1) 442 | # print repr(checkbox) 443 | # print dir(match), match.start(), match.span() 444 | col_start, col_stop = match.span() 445 | return sublime.Region( 446 | view.text_point(row, col_start), 447 | view.text_point(row, col_stop), 448 | ) 449 | 450 | 451 | class OrgmodeToggleCheckboxCommand(AbstractCheckboxCommand): 452 | 453 | def run(self, edit): 454 | view = self.view 455 | backup = [] 456 | for sel in view.sel(): 457 | if 'orgmode.checkbox' not in view.scope_name(sel.end()): 458 | continue 459 | backup.append(sel) 460 | checkbox = view.extract_scope(sel.end()) 461 | line = view.line(checkbox) 462 | self.toggle_checkbox(edit, line, recurse_up=True, recurse_down=True) 463 | view.sel().clear() 464 | for region in backup: 465 | view.sel().add(region) 466 | 467 | 468 | class OrgmodeRecalcCheckboxSummaryCommand(AbstractCheckboxCommand): 469 | 470 | def run(self, edit): 471 | view = self.view 472 | backup = [] 473 | for sel in view.sel(): 474 | if 'orgmode.checkbox.summary' not in view.scope_name(sel.end()): 475 | continue 476 | backup.append(sel) 477 | summary = view.extract_scope(sel.end()) 478 | line = view.line(summary) 479 | self.update_line(edit, line) 480 | view.sel().clear() 481 | for region in backup: 482 | view.sel().add(region) 483 | 484 | 485 | class OrgmodeLinkCompletions(sublime_plugin.EventListener): 486 | 487 | def on_query_completions(self, view, prefix, locations): 488 | import os 489 | from glob import glob 490 | # print 'view =', view 491 | # print 'preifx =', prefix 492 | # print 'locations =', locations 493 | location = locations[0] 494 | if not 'orgmode.link' in view.scope_name(location): 495 | return [] 496 | region = view.extract_scope(location) 497 | content = view.substr(region) 498 | inner_region = region 499 | if content.startswith('[[') and content.endswith(']]'): 500 | content = content[2:-2] 501 | inner_region = sublime.Region(region.begin() + 2, region.end() - 2) 502 | if not inner_region.contains(location): 503 | return [] 504 | content = view.substr(sublime.Region(inner_region.begin(), location)) 505 | content = os.path.expandvars(content) 506 | content = os.path.expanduser(content) 507 | # print 'region =', region 508 | # print 'content =', content 509 | path, base = os.path.split(content) 510 | # print 'split =', path, base 511 | if not len(path): 512 | path = os.path.dirname(view.file_name()) 513 | if not os.path.exists(path): 514 | path = os.path.join(os.path.dirname(view.file_name()), path) 515 | # print 'path =', path, base 516 | pattern = os.path.join(path, '%s*' % base) 517 | # print 'pattern =', pattern 518 | files = glob(pattern) 519 | basename = os.path.basename 520 | isdir = os.path.isdir 521 | for pos, item in enumerate(files[:]): 522 | expr = basename(item) 523 | snippet = basename(item) 524 | if isdir(item): 525 | expr += '/' 526 | snippet += '/' 527 | files[pos] = (expr, snippet) 528 | # print 'files =', files 529 | if not files: 530 | return [(base + '/', base)] 531 | return files 532 | 533 | 534 | class OrgmodeDateCompleter(sublime_plugin.EventListener): 535 | 536 | def on_query_completions(self, view, prefix, locations): 537 | if not has_file_ext(view, "org"): 538 | return [] 539 | self.settings = sublime.load_settings('orgmode.sublime-settings') 540 | self.date_format = self.settings.get( 541 | 'orgmode.autocomplete.date', "%Y-%m-%d %H:%M") 542 | self.date_format_cmd = self.settings.get( 543 | 'orgmode.autocomplete.date.cmd', "date") 544 | 545 | return [ 546 | (self.date_format_cmd, datetime.datetime.now().strftime( 547 | self.date_format)), 548 | ("week", str(datetime.datetime.now().isocalendar()[1])), 549 | ] 550 | 551 | def has_file_ext(view, ext): 552 | """Returns ``True`` if view has file extension ``ext``. 553 | ``ext`` may be specified with or without leading ``.``. 554 | """ 555 | if not view.file_name(): return False 556 | if not ext.strip().replace('.', ''): return False 557 | 558 | if not ext.startswith('.'): 559 | ext = '.' + ext 560 | 561 | return view.file_name().lower().endswith(ext) 562 | -------------------------------------------------------------------------------- /orgmode.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // Global 3 | "color_scheme": "Packages/orgmode/Color Scheme/orgmode.tmTheme", 4 | "word_wrap": true, 5 | "translate_tabs_to_spaces": true, 6 | "tab_size": 2, 7 | "auto_indent": true, 8 | "indent_subsequent_lines": true, 9 | "detect_indentation": false, 10 | "line_numbers": true, 11 | "save_on_focus_lost": true, 12 | "gutter": true, 13 | 14 | // autocomplete of "date" will insert current date with format 15 | "orgmode.autocomplete.date.cmd":"date", 16 | "orgmode.autocomplete.date":"%Y-%m-%d %H:%M", 17 | 18 | 19 | //orgmode resolvers 20 | //jira 21 | "orgmode.open_link.resolver.jira.url":"http://sandbox.onjira.com/browse/%s", 22 | "orgmode.open_link.resolver.jira.pattern":"^(jira|j):(?P.+)$", 23 | 24 | //redmine 25 | "orgmode.open_link.resolver.redmine.url":"http://google.org/issues/%s", 26 | "orgmode.open_link.resolver.redmine.pattern":"^(issue:|redmine:|#)(?P.+)$", 27 | 28 | //crucible 29 | "orgmode.open_link.resolver.crucible.url":"http://sandbox.fisheye.atlassian.com/cru/%s", 30 | "orgmode.open_link.resolver.crucible.pattern":"^(crucible|cru|cr):(?P.+)$", 31 | 32 | //email 33 | "orgmode.open_link.resolver.email.url":"mailto:%s", 34 | "orgmode.open_link.resolver.email.pattern":"^(?Pemail|mailto):(?P[^/]+)(/(?P.+))?$", 35 | 36 | //fisheye 37 | "orgmode.open_link.resolver.fisheye.url":"http://sandbox.fisheye.atlassian.com/changelog/%s", 38 | "orgmode.open_link.resolver.fisheye.pattern":"^(fisheye|fish|fe):(?P[^/]+)(/(?P.+))?$", 39 | 40 | //prompt 41 | "orgmode.open_link.resolver.prompt.pattern":"^(cmd:|prompt:)(?P.+)$", 42 | 43 | //local_file 44 | "orgmode.open_link.resolver.local_file.force_into_sublime":"'*.txt', '*.org', '*.py', '*.rb', '*.html', '*.css', '*.js', '*.php', '*.c', '*.cpp', '*.h'", 45 | "orgmode.open_link.resolver.local_file.pattern":"^(?P.+?)(?::(?P\\d+)(?::(?P\\d+))?)?$", 46 | 47 | 48 | 49 | // HelpIt 50 | "cocoa" : { 51 | "url" : "http://www.google.com/search?btnI=1&q=site:developer.apple.com+%s" 52 | }, 53 | "objc" : { 54 | "url" : "http://www.google.com/search?btnI=1&q=site:developer.apple.com+%s" 55 | }, 56 | "java" : { 57 | "url" : "http://www.google.com/search?btnI=1&q=site:docs.oracle.com+javadoc+%s" 58 | }, 59 | "python" : { 60 | "url" : "http://docs.python.org/search.html?q=%s" 61 | }, 62 | "php" : { 63 | "url" : "http://php.net/%s" 64 | }, 65 | "less" : { 66 | "map" : "css" 67 | }, 68 | "js" : { 69 | "sub" : [{ 70 | "contains" : "$", 71 | "url" : "http://api.jquery.com/%s", 72 | "remove" : "\\$.*\\." 73 | }] 74 | }, 75 | "html" : "http://www.google.com/search?btnI=1&q=site:w3schools.com/html5+tag+%s", 76 | "plain": "http://answers.com/%s" 77 | } 78 | -------------------------------------------------------------------------------- /orgmode.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | org 8 | tasks 9 | 10 | keyEquivalent 11 | ^~P 12 | name 13 | orgmode 14 | patterns 15 | 16 | 17 | name 18 | orgmode.page 19 | match 20 | ^\s*\-\-\- [^\n]* 21 | 22 | 23 | name 24 | orgmode.break 25 | match 26 | ^\s*[~]+ [^\n]* 27 | 28 | 29 | name 30 | orgmode.headline 31 | match 32 | ^\s*[*]+ [^\[\]:\n]* 33 | 34 | 35 | name 36 | orgmode.deadline 37 | match 38 | DEADLINE: <\d{4}-\d{2}-\d{2}(?:\s*\w{3}>|>) 39 | 40 | 41 | name 42 | orgmode.scheduled 43 | match 44 | SCHEDULED: <\d{4}-\d{2}-\d{2}(?:\s*\w{3}>|>) 45 | 46 | 47 | name 48 | orgmode.tack 49 | match 50 | ^\s*\- 51 | 52 | 53 | name 54 | orgmode.follow_up 55 | match 56 | ^\s*(\-\>|\=\>) 57 | 58 | 59 | name 60 | orgmode.checkbox 61 | match 62 | (\[[xX\- ]\])\s? 63 | 64 | 65 | name 66 | orgmode.checkbox.summary 67 | match 68 | (\[\d*[/]\d*\]) 69 | 70 | 71 | name 72 | orgmode.link 73 | match 74 | \[\[(.+?)?\]\] 75 | 76 | 77 | name 78 | orgmode.link.internal.number 79 | match 80 | \{(\d+)\} 81 | 82 | 83 | name 84 | orgmode.link.internal.headline 85 | match 86 | \{\{(.+?)\}\} 87 | 88 | 89 | contentName 90 | text source 91 | begin 92 | \[code\]\s* 93 | end 94 | \s*\[/code\] 95 | patterns 96 | 97 | 98 | include 99 | #python_exception.reference 100 | 101 | 102 | 103 | 104 | name 105 | orgmode.tags 106 | match 107 | (^|\s):[\w\d:]+: 108 | 109 | 110 | name 111 | orgmode.todo 112 | match 113 | TODO|WORKING|DONE 114 | 115 | 116 | name 117 | orgmode.python.traceback 118 | begin 119 | ^\s*Traceback \(most recent call last\):\s*$ 120 | end 121 | ^\s*\w+: .+$ 122 | patterns 123 | 124 | 125 | include 126 | #python_exception.reference 127 | 128 | 129 | 130 | 131 | 132 | scopeName 133 | text.orgmode 134 | uuid 135 | D0287542-2284-452C-8648-B885B3E16B6F 136 | 137 | 138 | -------------------------------------------------------------------------------- /orgmode_store.py: -------------------------------------------------------------------------------- 1 | from gzip import GzipFile 2 | from os import makedirs 3 | from os.path import dirname, join, abspath 4 | from pickle import load, dump 5 | import os 6 | from os.path import dirname, realpath 7 | import sublime 8 | import sublime_plugin 9 | import logging as log 10 | 11 | log.basicConfig(level=log.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') 12 | 13 | class OrgmodeStore(sublime_plugin.EventListener): 14 | 15 | def __init__(self, *args, **kwargs): 16 | self.debug = False 17 | self.db = {} 18 | self.store = os.path.join(dirname(dirname(realpath(__file__))), 19 | 'Settings', 20 | 'orgmode-store.bin.gz') 21 | log.debug("Orgmode settings path: " + self.store) 22 | try: 23 | makedirs(dirname(self.store)) 24 | except: 25 | pass 26 | try: 27 | with GzipFile(self.store, 'rb') as f: 28 | self.db = load(f) 29 | except: 30 | self.db = {} 31 | 32 | self.on_load(sublime.active_window().active_view()) 33 | for window in sublime.windows(): 34 | self.on_load(window.active_view()) 35 | 36 | 37 | def on_load(self, view): 38 | self.restore(view, 'on_load') 39 | 40 | def on_deactivated(self, view): 41 | window = view.window() 42 | if not window: 43 | window = sublime.active_window() 44 | index = window.get_view_index(view) 45 | if index != (-1, -1): # if the view was not closed 46 | self.save(view, 'on_deactivated') 47 | 48 | def on_activated(self, view): 49 | self.restore(view, 'on_activated') 50 | 51 | def on_pre_close(self, view): 52 | self.save(view, 'on_pre_close') 53 | 54 | def on_pre_save(self, view): 55 | self.save(view, 'on_pre_save') 56 | 57 | def save(self, view, where='unknow'): 58 | if view is None or not view.file_name(): 59 | return 60 | 61 | if view.is_loading(): 62 | sublime.set_timeout(lambda: self.save(view, where), 100) 63 | return 64 | 65 | _filename = view.file_name() 66 | if _filename not in self.db: 67 | self.db[_filename] = {} 68 | 69 | # if the result of the new collected data is different 70 | # from the old data, then will write to disk 71 | # this will hold the old value for comparison 72 | old_db = dict(self.db[_filename]) 73 | 74 | # if the size of the view change outside the application skip 75 | # restoration 76 | self.db[_filename]['id'] = int(view.size()) 77 | 78 | # marks 79 | self.db[_filename]['m'] = [[item.a, item.b] 80 | for item in view.get_regions("mark")] 81 | if self.debug: 82 | log.debug('marks: ' + str(self.db[_filename]['m'])) 83 | 84 | # previous folding save, to be able to refold 85 | if 'f' in self.db[_filename] and list(self.db[_filename]['f']) != []: 86 | self.db[_filename]['pf'] = list(self.db[_filename]['f']) 87 | 88 | # folding 89 | self.db[_filename]['f'] = [[item.a, item.b] for item in view.folded_regions()] 90 | if self.debug: 91 | log.debug('fold: ' + str(self.db[_filename]['f'])) 92 | 93 | 94 | if not self.db[_filename]['f'] and not self.db[_filename]['m']: 95 | if self.debug: 96 | log.debug("Nothing to save") 97 | return 98 | 99 | # write to disk only if something changed 100 | if old_db != self.db[_filename] or where == 'on_deactivated': 101 | log.debug("Orgmode settings write path: " + self.store) 102 | with GzipFile(self.store, 'wb') as f: 103 | dump(self.db, f, -1) 104 | 105 | def restore(self, view, where='unknow'): 106 | if view is None or not view.file_name(): 107 | return 108 | 109 | if view.is_loading(): 110 | sublime.set_timeout(lambda: self.restore(view, where), 100) 111 | return 112 | 113 | _filename = view.file_name() 114 | if _filename in self.db: 115 | if self.debug: 116 | log.debug('-----------------------------------') 117 | log.debug('RESTORING from: ' + where) 118 | log.debug('file: ' + view.file_name()) 119 | # fold 120 | rs = [] 121 | for r in self.db[_filename]['f']: 122 | rs.append(sublime.Region(int(r[0]), int(r[1]))) 123 | if len(rs): 124 | view.fold(rs) 125 | if self.debug: 126 | log.debug("fold: " + str(rs)) 127 | 128 | # marks 129 | rs = [] 130 | for r in self.db[_filename]['m']: 131 | rs.append(sublime.Region(int(r[0]), int(r[1]))) 132 | if len(rs): 133 | view.add_regions( 134 | "mark", rs, "mark", "dot", sublime.HIDDEN | sublime.PERSISTENT) 135 | if self.debug: 136 | log.debug('marks: ' + str(self.db[_filename]['m'])) 137 | 138 | 139 | class OrgmodeFoldingCommand(sublime_plugin.TextCommand): 140 | """ 141 | Bind to TAB key, and if the current line is not 142 | a headline, a \t would be inserted. 143 | """ 144 | 145 | def run(self, edit): 146 | (row,col) = self.view.rowcol(self.view.sel()[0].begin()) 147 | line = row + 1 148 | log.debug(line) 149 | for s in self.view.sel(): 150 | r = self.view.full_line(s) 151 | if self._is_region_folded(r.b + 1, self.view): 152 | self.view.run_command("unfold") 153 | return 154 | 155 | pt = self.view.text_point(line, 0) 156 | self.view.sel().clear() 157 | self.view.sel().add(sublime.Region(pt)) 158 | self.view.run_command("fold") 159 | 160 | def _is_region_folded(self, region, view): 161 | for i in view.folded_regions(): 162 | if i.contains(region): 163 | return True 164 | return False 165 | -------------------------------------------------------------------------------- /packages.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_version": "2.0", 3 | "packages": [ 4 | { 5 | "name": "orgmode", 6 | "author": "Daniel Magnusson(danielmagnussons)", 7 | "homepage": "https://github.com/danielmagnussons/orgmode", 8 | "donate": "https://www.gittip.com/danielmagnussons/", 9 | "details": "https://github.com/danielmagnussons/orgmode", 10 | "labels": ["text manipulation", "text navigation", "formatting", "todo", "color scheme"], 11 | "releases": [ 12 | { 13 | "sublime_text": "*", 14 | "details": "https://github.com/danielmagnussons/orgmode/tags" 15 | } 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /resolver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielmagnussons/orgmode/73d52ba15a39e0c0649ed268ca1f268800a990aa/resolver/__init__.py -------------------------------------------------------------------------------- /resolver/abstract.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys 3 | import subprocess 4 | import sublime 5 | 6 | 7 | DEFAULT_OPEN_LINK_COMMANDS = dict( 8 | # Standard universal can opener for OSX. 9 | darwin=['open'], 10 | win32=['cmd', '/C', 'start'], 11 | linux=['xdg-open'], 12 | ) 13 | 14 | 15 | class AbstractLinkResolver(object): 16 | 17 | def __init__(self, view): 18 | self.view = view 19 | self.settings = sublime.load_settings('orgmode.sublime-settings') 20 | self.link_commands = self.settings.get( 21 | 'orgmode.open_link.resolver.abstract.commands', DEFAULT_OPEN_LINK_COMMANDS) 22 | 23 | def extract(self, content): 24 | return content 25 | 26 | def replace(self, content): 27 | return content 28 | 29 | def resolve(self, content): 30 | match = self.extract(content) 31 | if not match: 32 | return None 33 | return self.replace(match) 34 | 35 | def get_link_command(self): 36 | platform = sys.platform 37 | for key, val in self.link_commands.items(): 38 | if key in platform: 39 | return val 40 | return None 41 | 42 | def execute(self, content): 43 | command = self.get_link_command() 44 | if not command: 45 | sublime.error_message( 46 | 'Could not get link opener command.\nPlatform not yet supported.') 47 | return None 48 | 49 | if sys.version_info[0] < 3: 50 | content = content.encode(sys.getfilesystemencoding()) 51 | 52 | cmd = command + [content] 53 | arg_list_wrapper = self.settings.get( 54 | "orgmode.open_link.resolver.abstract.arg_list_wrapper", []) 55 | if arg_list_wrapper: 56 | cmd = arg_list_wrapper + [' '.join(cmd)] 57 | source_filename = '\"' + self.view.file_name() + '\"' 58 | cmd += [source_filename] 59 | if sys.platform != 'win32': 60 | cmd += ['--origin', source_filename, '--quiet'] 61 | 62 | print('*****') 63 | print(repr(content), content) 64 | print(cmd) 65 | sublime.status_message('Executing: %s' % cmd) 66 | 67 | if sys.platform != 'win32': 68 | process = subprocess.Popen( 69 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 70 | else: 71 | process = subprocess.Popen( 72 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 73 | 74 | stdout, stderr = process.communicate() 75 | if stdout: 76 | stdout = str(stdout, sys.getfilesystemencoding()) 77 | sublime.status_message(stdout) 78 | if stderr: 79 | stderr = str(stderr, sys.getfilesystemencoding()) 80 | sublime.error_message(stderr) 81 | 82 | 83 | class AbstractRegexLinkResolver(AbstractLinkResolver): 84 | 85 | def __init__(self, view): 86 | self.view = view 87 | self.settings = sublime.load_settings('orgmode.sublime-settings') 88 | self.link_commands = self.settings.get( 89 | 'orgmode.open_link.resolver.abstract.commands', DEFAULT_OPEN_LINK_COMMANDS) 90 | self.regex = None 91 | 92 | def extract(self, content): 93 | if self.regex is None: 94 | return content 95 | match = self.regex.match(content) 96 | return match 97 | 98 | def replace(self, match): 99 | return match.groups()[1] 100 | -------------------------------------------------------------------------------- /resolver/crucible.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from .abstract import AbstractRegexLinkResolver 4 | 5 | 6 | PATTERN_SETTING = 'orgmode.open_link.resolver.crucible.pattern' 7 | PATTERN_DEFAULT = r'^(crucible|cru|cr):(?P.+)$' 8 | URL_SETTING = 'orgmode.open_link.resolver.crucible.url' 9 | URL_DEFAULT = 'http://sandbox.fisheye.atlassian.com/cru/%s' 10 | 11 | 12 | class Resolver(AbstractRegexLinkResolver): 13 | 14 | def __init__(self, view): 15 | super(Resolver, self).__init__(view) 16 | get = self.settings.get 17 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 18 | self.regex = re.compile(pattern) 19 | self.url = get(URL_SETTING, URL_DEFAULT) 20 | 21 | def replace(self, match): 22 | return self.url % match.group('review') 23 | -------------------------------------------------------------------------------- /resolver/email.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from .abstract import AbstractRegexLinkResolver 4 | 5 | 6 | PATTERN_SETTING = 'orgmode.open_link.resolver.email.pattern' 7 | PATTERN_DEFAULT = r'^(?Pemail|mailto):(?P[^/]+)(/(?P.+))?$' 8 | URL_SETTING = 'orgmode.open_link.resolver.email.url' 9 | URL_DEFAULT = 'mailto:%s' 10 | 11 | 12 | class Resolver(AbstractRegexLinkResolver): 13 | 14 | def __init__(self, view): 15 | super(Resolver, self).__init__(view) 16 | get = self.settings.get 17 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 18 | self.regex = re.compile(pattern) 19 | self.url = get(URL_SETTING, URL_DEFAULT) 20 | 21 | def replace(self, match): 22 | match = match.groupdict() 23 | if match['type'] == 'mailto': 24 | url = self.url % match['email'] 25 | if match['subject']: 26 | url += '?subject=%s' % match['subject'] 27 | return url 28 | if match['type'] == 'email': 29 | return dict(email=match['email'], path=match['subject']) 30 | 31 | def execute(self, content): 32 | if isinstance(content, dict) and 'email' in content: 33 | import sublime 34 | # TODO Implement email opener here. 35 | sublime.error_message('Email opener not implemented yet.') 36 | raise NotImplemented() 37 | else: 38 | return super(Resolver, self).execute(content) 39 | -------------------------------------------------------------------------------- /resolver/fisheye.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from .abstract import AbstractRegexLinkResolver 4 | 5 | 6 | PATTERN_SETTING = 'orgmode.open_link.resolver.fisheye.pattern' 7 | PATTERN_DEFAULT = r'^(fisheye|fish|fe):(?P[^/]+)(/(?P.+))?$' 8 | URL_SETTING = 'orgmode.open_link.resolver.fisheye.url' 9 | URL_DEFAULT = 'http://sandbox.fisheye.atlassian.com/changelog/%s' 10 | 11 | 12 | class Resolver(AbstractRegexLinkResolver): 13 | 14 | def __init__(self, view): 15 | super(Resolver, self).__init__(view) 16 | get = self.settings.get 17 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 18 | self.regex = re.compile(pattern) 19 | self.url = get(URL_SETTING, URL_DEFAULT) 20 | 21 | def replace(self, match): 22 | match = match.groupdict() 23 | url = self.url % match['repo'] 24 | if match['rev']: 25 | url += '?cs=%s' % match['rev'] 26 | return url 27 | -------------------------------------------------------------------------------- /resolver/http.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import re 4 | import subprocess 5 | import sublime 6 | from .abstract import AbstractRegexLinkResolver 7 | 8 | try: 9 | import urllib.request, urllib.parse, urllib.error 10 | except ImportError: 11 | import urllib 12 | 13 | 14 | 15 | PATTERN_SETTING = 'orgmode.open_link.resolver.http.pattern' 16 | PATTERN_DEFAULT = r'^(http):(?P.+)$' 17 | URL_SETTING = 'orgmode.open_link.resolver.http.url' 18 | URL_DEFAULT = 'http:%s' 19 | 20 | 21 | DEFAULT_OPEN_HTTP_LINK_COMMANDS = dict( 22 | darwin=['open'], 23 | win32=['cmd', '/C'], 24 | linux=['xdg-open'], 25 | ) 26 | 27 | 28 | class Resolver(AbstractRegexLinkResolver): 29 | 30 | def __init__(self, view): 31 | super(Resolver, self).__init__(view) 32 | get = self.settings.get 33 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 34 | self.regex = re.compile(pattern) 35 | self.url = get(URL_SETTING, URL_DEFAULT) 36 | self.link_commands = self.settings.get( 37 | 'orgmode.open_link.resolver.abstract.commands', DEFAULT_OPEN_HTTP_LINK_COMMANDS) 38 | 39 | def replace(self, match): 40 | return self.url % match.group('url') 41 | 42 | def execute(self, content): 43 | command = self.get_link_command() 44 | if not command: 45 | sublime.error_message( 46 | 'Could not get link opener command.\nNot yet supported.') 47 | return None 48 | 49 | # cmd.exe quote is needed, http://ss64.com/nt/syntax-esc.html 50 | # escape these: ^\ ^& ^| ^> ^< ^^ 51 | if sys.platform == 'win32': 52 | content = content.replace("^", "^^") 53 | content = content.replace("&", "^&") 54 | content = content.replace("\\", "^\\") 55 | content = content.replace("|", "^|") 56 | content = content.replace("<", "^<") 57 | content = content.replace(">", "^>") 58 | 59 | 60 | if sys.version_info[0] < 3: 61 | content = content.encode(sys.getfilesystemencoding()) 62 | 63 | if sys.platform != 'win32': 64 | cmd = command + [content] 65 | else: 66 | cmd = command + ['start ' + content] 67 | 68 | print('HTTP*****') 69 | print(repr(content), content) 70 | print(repr(cmd)) 71 | print(cmd) 72 | sublime.status_message('Executing: %s' % cmd) 73 | if sys.platform != 'win32': 74 | process = subprocess.Popen( 75 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 76 | else: 77 | process = subprocess.Popen( 78 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 79 | 80 | stdout, stderr = process.communicate() 81 | if stdout: 82 | stdout = str(stdout, sys.getfilesystemencoding()) 83 | sublime.status_message(stdout) 84 | if stderr: 85 | stderr = str(stderr, sys.getfilesystemencoding()) 86 | sublime.error_message(stderr) 87 | -------------------------------------------------------------------------------- /resolver/https.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import sys 4 | import subprocess 5 | import sublime 6 | from .abstract import AbstractRegexLinkResolver 7 | 8 | try: 9 | import urllib.request, urllib.parse, urllib.error 10 | except ImportError: 11 | import urllib 12 | 13 | 14 | PATTERN_SETTING = 'orgmode.open_link.resolver.https.pattern' 15 | PATTERN_DEFAULT = r'^(https):(?P.+)$' 16 | URL_SETTING = 'orgmode.open_link.resolver.https.url' 17 | URL_DEFAULT = 'https:%s' 18 | 19 | DEFAULT_OPEN_HTTP_LINK_COMMANDS = dict( 20 | darwin=['open'], 21 | win32=['cmd', '/C'], 22 | linux=['xdg-open'], 23 | ) 24 | 25 | 26 | class Resolver(AbstractRegexLinkResolver): 27 | 28 | def __init__(self, view): 29 | super(Resolver, self).__init__(view) 30 | get = self.settings.get 31 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 32 | self.regex = re.compile(pattern) 33 | self.url = get(URL_SETTING, URL_DEFAULT) 34 | self.link_commands = self.settings.get( 35 | 'orgmode.open_link.resolver.abstract.commands', DEFAULT_OPEN_HTTP_LINK_COMMANDS) 36 | 37 | def replace(self, match): 38 | return self.url % match.group('url') 39 | 40 | def execute(self, content): 41 | command = self.get_link_command() 42 | if not command: 43 | sublime.error_message( 44 | 'Could not get link opener command.\nNot yet supported.') 45 | return None 46 | 47 | # cmd.exe quote is needed, http://ss64.com/nt/syntax-esc.html 48 | # escape these: ^\ ^& ^| ^> ^< ^^ 49 | if sys.platform == 'win32': 50 | content = content.replace("^", "^^") 51 | content = content.replace("&", "^&") 52 | content = content.replace("\\", "^\\") 53 | content = content.replace("|", "^|") 54 | content = content.replace("<", "^<") 55 | content = content.replace(">", "^>") 56 | 57 | if sys.version_info[0] < 3: 58 | content = content.encode(sys.getfilesystemencoding()) 59 | 60 | if sys.platform != 'win32': 61 | cmd = command + [content] 62 | else: 63 | cmd = command + ['start ' + content] 64 | 65 | print('HTTP*****') 66 | print(repr(content), content) 67 | print(repr(cmd)) 68 | print(cmd) 69 | sublime.status_message('Executing: %s' % cmd) 70 | if sys.platform != 'win32': 71 | process = subprocess.Popen( 72 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 73 | else: 74 | process = subprocess.Popen( 75 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 76 | 77 | stdout, stderr = process.communicate() 78 | if stdout: 79 | stdout = str(stdout, sys.getfilesystemencoding()) 80 | sublime.status_message(stdout) 81 | if stderr: 82 | stderr = str(stderr, sys.getfilesystemencoding()) 83 | sublime.error_message(stderr) 84 | -------------------------------------------------------------------------------- /resolver/jira.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from .abstract import AbstractRegexLinkResolver 4 | 5 | 6 | PATTERN_SETTING = 'orgmode.open_link.resolver.jira.pattern' 7 | PATTERN_DEFAULT = r'^(jira|j):(?P.+)$' 8 | URL_SETTING = 'orgmode.open_link.resolver.jira.url' 9 | URL_DEFAULT = 'http://sandbox.onjira.com/browse/%s' 10 | 11 | 12 | class Resolver(AbstractRegexLinkResolver): 13 | 14 | def __init__(self, view): 15 | super(Resolver, self).__init__(view) 16 | get = self.settings.get 17 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 18 | self.regex = re.compile(pattern) 19 | self.url = get(URL_SETTING, URL_DEFAULT) 20 | 21 | def replace(self, match): 22 | return self.url % match.group('issue') 23 | -------------------------------------------------------------------------------- /resolver/local_file.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import os 4 | from fnmatch import fnmatch 5 | import sublime 6 | from .abstract import AbstractLinkResolver 7 | 8 | 9 | PATTERN_SETTING = 'orgmode.open_link.resolver.local_file.pattern' 10 | PATTERN_DEFAULT = r'^(?P.+?)(?::(?P\d+)(?::(?P\d+))?)?$' 11 | 12 | FORCE_LOAD_SETTING = 'orgmode.open_link.resolver.local_file.force_into_sublime' 13 | FORCE_LOAD_DEFAULT = ['*.txt', '*.org', '*.py', '*.rb', 14 | '*.html', '*.css', '*.js', '*.php', '*.c', '*.cpp', '*.h'] 15 | 16 | 17 | class Resolver(AbstractLinkResolver): 18 | 19 | ''' 20 | @todo: If the link is a local org-file open it directly via sublime, otherwise use OPEN_LINK_COMMAND. 21 | ''' 22 | 23 | def __init__(self, view): 24 | super(Resolver, self).__init__(view) 25 | get = self.settings.get 26 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 27 | self.regex = re.compile(pattern) 28 | self.force_load_patterns = get(FORCE_LOAD_SETTING, FORCE_LOAD_DEFAULT) 29 | 30 | def file_is_excluded(self, filepath): 31 | basename = os.path.basename(filepath) 32 | for pattern in self.force_load_patterns: 33 | if fnmatch(basename, pattern): 34 | print('found in force_load_patterns') 35 | return False 36 | return True 37 | 38 | folder_exclude_patterns = self.settings.get('folder_exclude_patterns') 39 | if basename in folder_exclude_patterns: 40 | print('found in folder_exclude_patterns') 41 | return True 42 | file_exclude_patterns = self.settings.get('file_exclude_patterns') 43 | for pattern in file_exclude_patterns: 44 | if fnmatch(basename, pattern): 45 | print('found in file_exclude_patterns') 46 | return True 47 | return False 48 | 49 | def expand_path(self, filepath): 50 | filepath = os.path.expandvars(filepath) 51 | filepath = os.path.expanduser(filepath) 52 | 53 | match = self.regex.match(filepath) 54 | if match: 55 | filepath, row, col = match.group( 56 | 'filepath'), match.group('row'), match.group('col') 57 | else: 58 | row = None 59 | col = None 60 | 61 | drive, filepath = os.path.splitdrive(filepath) 62 | if not filepath.startswith('/'): # If filepath is relative... 63 | cwd = os.path.dirname(self.view.file_name()) 64 | testfile = os.path.join(cwd, filepath) 65 | if os.path.exists(testfile): # See if it exists here... 66 | filepath = testfile 67 | 68 | filepath = ''.join([drive, filepath]) if drive else filepath 69 | print('filepath: ' + filepath) 70 | if not self.file_is_excluded(filepath): 71 | if row: 72 | filepath += ':%s' % row 73 | if col: 74 | filepath += ':%s' % col 75 | print('file_is_excluded') 76 | self.view.window().open_file(filepath, sublime.ENCODED_POSITION) 77 | return True 78 | 79 | return filepath 80 | 81 | def replace(self, content): 82 | content = self.expand_path(content) 83 | return content 84 | 85 | def execute(self, content): 86 | if content is not True: 87 | print('normal open') 88 | return super(Resolver, self).execute(content) 89 | -------------------------------------------------------------------------------- /resolver/prompt.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import sys 4 | import subprocess 5 | import sublime 6 | from .abstract import AbstractRegexLinkResolver 7 | 8 | DEFAULT_OPEN_PROMPT_LINK_COMMANDS = dict( 9 | darwin=['open', '-a', 'Terminal'], 10 | win32=['cmd'], 11 | linux=['gnome-terminal'], 12 | ) 13 | 14 | 15 | PATTERN_SETTING = 'orgmode.open_link.resolver.prompt.pattern' 16 | PATTERN_DEFAULT = r'^(cmd:|prompt:)(?P.+)$' 17 | PROMPT_SETTING = 'orgmode.open_link.resolver.prompt.path' 18 | PROMPT_DEFAULT_WIN32 = '%s' 19 | PROMPT_DEFAULT_LINUX = '--working-directory=%s' 20 | 21 | 22 | class Resolver(AbstractRegexLinkResolver): 23 | 24 | def __init__(self, view): 25 | super(Resolver, self).__init__(view) 26 | get = self.settings.get 27 | self.link_commands = self.settings.get( 28 | 'orgmode.open_link.resolver.abstract.commands', DEFAULT_OPEN_PROMPT_LINK_COMMANDS) 29 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 30 | self.regex = re.compile(pattern) 31 | if sys.platform == 'win32' or sys.platform == 'darwin': 32 | self.url = get(PROMPT_SETTING, PROMPT_DEFAULT_WIN32) 33 | else: 34 | self.url = get(PROMPT_SETTING, PROMPT_DEFAULT_LINUX) 35 | 36 | def replace(self, match): 37 | return self.url % match.group('path') 38 | 39 | def get_link_command(self): 40 | platform = sys.platform 41 | for key, val in self.link_commands.items(): 42 | if key in platform: 43 | return val 44 | return None 45 | 46 | def execute(self, content): 47 | command = self.get_link_command() 48 | if not command: 49 | sublime.error_message( 50 | 'Could not get link opener command.\nNot yet supported.') 51 | return None 52 | 53 | if sys.version_info[0] < 3: 54 | content = content.encode(sys.getfilesystemencoding()) 55 | 56 | if sys.platform != 'win32': 57 | cmd = command + [content] 58 | else: 59 | cmd = 'cmd /C start cmd.exe /K "cd /d '+content+'"' 60 | 61 | print('PROMPT*****') 62 | print(repr(content)) 63 | print(cmd) 64 | # \"cd /d c:\dev\apps\"' is not recognized as an internal or external command, 65 | sublime.status_message('Executing: %s' % cmd) 66 | if sys.platform != 'win32': 67 | process = subprocess.Popen( 68 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 69 | else: 70 | process = subprocess.Popen( 71 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 72 | 73 | stdout, stderr = process.communicate() 74 | if stdout: 75 | stdout = str(stdout, sys.getfilesystemencoding()) 76 | sublime.status_message(stdout) 77 | if stderr: 78 | stderr = str(stderr, sys.getfilesystemencoding()) 79 | sublime.error_message(stderr) 80 | -------------------------------------------------------------------------------- /resolver/redmine.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from .abstract import AbstractRegexLinkResolver 4 | 5 | 6 | PATTERN_SETTING = 'orgmode.open_link.resolver.redmine.pattern' 7 | PATTERN_DEFAULT = r'^(issue:|redmine:|#)(?P.+)$' 8 | URL_SETTING = 'orgmode.open_link.resolver.redmine.url' 9 | URL_DEFAULT = 'http://redmine.org/issues/%s' 10 | 11 | 12 | class Resolver(AbstractRegexLinkResolver): 13 | 14 | def __init__(self, view): 15 | super(Resolver, self).__init__(view) 16 | get = self.settings.get 17 | pattern = get(PATTERN_SETTING, PATTERN_DEFAULT) 18 | self.regex = re.compile(pattern) 19 | self.url = get(URL_SETTING, URL_DEFAULT) 20 | 21 | def replace(self, match): 22 | return self.url % match.group('issue') 23 | -------------------------------------------------------------------------------- /snippets/break.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | b 4 | text.orgmode 5 | break 6 | 7 | -------------------------------------------------------------------------------- /snippets/checkbox_checked.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | cc 4 | text.orgmode 5 | checkbox checked 6 | 7 | -------------------------------------------------------------------------------- /snippets/checkbox_summary.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | cs 4 | text.orgmode 5 | checkbox summary 6 | 7 | -------------------------------------------------------------------------------- /snippets/checkbox_unchecked.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | c 4 | text.orgmode 5 | checkbox unchecked 6 | 7 | -------------------------------------------------------------------------------- /snippets/code.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 5 | code 6 | text.orgmode 7 | code block 8 | 9 | -------------------------------------------------------------------------------- /snippets/extlink.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | l 4 | text.orgmode 5 | external link 6 | 7 | -------------------------------------------------------------------------------- /snippets/followup.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | ${0:CONTENT}]]> 3 | f 4 | text.orgmode 5 | follow up 6 | 7 | -------------------------------------------------------------------------------- /snippets/headline.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | h 4 | text.orgmode 5 | headline 6 | 7 | -------------------------------------------------------------------------------- /snippets/headline2.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | hh 4 | text.orgmode 5 | headline 2 6 | 7 | -------------------------------------------------------------------------------- /snippets/headline3.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | hhh 4 | text.orgmode 5 | headline 3 6 | 7 | -------------------------------------------------------------------------------- /snippets/intlink.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | i 4 | text.orgmode 5 | internal link 6 | 7 | -------------------------------------------------------------------------------- /snippets/intlink2.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | ii 4 | text.orgmode 5 | internal headline link 6 | 7 | -------------------------------------------------------------------------------- /snippets/multitag.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | : 4 | text.orgmode 5 | tag 6 | 7 | -------------------------------------------------------------------------------- /snippets/page.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | p 4 | text.orgmode 5 | page 6 | 7 | -------------------------------------------------------------------------------- /snippets/sumup.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | ${0:CONTENT}]]> 3 | ff 4 | text.orgmode 5 | sum up 6 | 7 | -------------------------------------------------------------------------------- /snippets/tack.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | - 4 | text.orgmode 5 | tack 6 | 7 | -------------------------------------------------------------------------------- /snippets/tack_checkbox_checked.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | -cc 4 | text.orgmode 5 | tack checkbox checked 6 | 7 | -------------------------------------------------------------------------------- /snippets/tack_checkbox_unchecked.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | -c 4 | text.orgmode 5 | tack checkbox unchecked 6 | 7 | -------------------------------------------------------------------------------- /snippets/tack_checkbox_unchecked_extlink.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | -cl 4 | text.orgmode 5 | tack checkbox unchecked external link 6 | 7 | -------------------------------------------------------------------------------- /snippets/tack_done.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | -d 4 | text.orgmode 5 | tack done 6 | 7 | -------------------------------------------------------------------------------- /snippets/tack_todo.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | -t 4 | text.orgmode 5 | tack todo 6 | 7 | -------------------------------------------------------------------------------- /snippets/tack_working.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | -w 4 | text.orgmode 5 | tack working 6 | 7 | -------------------------------------------------------------------------------- /snippets/tag.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | t 4 | text.orgmode 5 | tag 6 | 7 | --------------------------------------------------------------------------------