Repository: irrationalistic/atom-tasks
Branch: master
Commit: a35f37e31153
Files: 20
Total size: 184.7 KB
Directory structure:
gitextract_py66d33m/
├── .gitignore
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── demo.todo
├── keymaps/
│ └── tasks.cson
├── lib/
│ ├── tasks.coffee
│ ├── tasks.cson
│ ├── tasksUtilities.coffee
│ ├── touchbar.coffee
│ └── views/
│ └── task-status-view.coffee
├── menus/
│ └── tasks.cson
├── package.json
├── project.todo
├── settings/
│ └── tasks.cson
├── spec/
│ ├── benchmark.todo
│ ├── complexMarkers.todo
│ ├── sample.taskpaper
│ └── tasks-spec.coffee
└── styles/
└── tasks.less
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
npm-debug.log
node_modules
test.todo
================================================
FILE: CHANGELOG.md
================================================
## 2.10.1
* Fix bug with requiring built-in season lib as opposed to node_modules one. Fixes #93
## 2.10.0
* Fix bug with atom 1.24 new grammar system by writing dynamic grammar
to intermediate file, fixes #92, #88
* Merge fix for indentation (thanks @javs)
## 2.9.1
* Fix bug with "new task" action in touchbar
## 2.9.0
* Add osx touchbar support (thanks @paulroub!)
## 2.8.0
* Escape parentheses when adding tags (thanks @paulroub), fixes #74
* Fix for timezones in tests (thanks @paulroub)
## 2.7.0
* Adds setting for applying timestamp when an item is converted to task (#76)
* Re-enabled and updated all tests
* Fix markdown in text
* Fix completion count in taskbar (#82)
* Updated moment version
## 2.6.7
* Fixes #78 (thanks @stefanthaler and @Guerillero)
## 2.6.6
* Fixes #63 where I missed the calls in the util file
* Support empty lines when calculating projects (#69)
## 2.6.5
* Fix for syntax warning. Thanks to @blimmer!
## 2.6.4
* Fix for deprecated displayBuffer (#63)
## 2.6.3
* Fix for markdown in task items
## 2.6.2
* Fix for error when tasks file is in focus on load
## 2.6.1
* Fix for missing indentLevel code
## 2.6.0
* Updated after breaking changes:
* Removed dependency on displayBuffer
* Fixes bugs with task management
* Tests are broken, so they are removed temporarily until a solution is found
## 2.5.1
* Added timestamp command to menu and readme
## 2.5.0
* Rewrote grammar to prevent extra markers from highlighting
* Added support for highlighting urls inline
* Added new command for adding/updating the timestamp on a task
## 2.4.0
* Added hotkey for convert-to-task
## 2.3.0
* Added support for markdown highlighting in tasks
## 2.2.0
* Added setting for controlling the attribute marker
## 2.1.0
* Added setting for controlling the archive separator
## 2.0.2
* Fix for removal of bufferColumnForToken
## 2.0.1
* Fix for bug with urls in tasks
## 2.0.0 - Big Ol Rewrite
* Major rewrite of core code
* Moved archive tasks hotkey to cmd-shift-a
* Convert a non-task to a task
* Optimized performance for larger files
* Colors improved
* Supports line wrapping
* Added status bar item for progress
* Added utility functions for managing tags
* Supports complex tokens like [ ], [x]
* Menu commands have spaces in names
## 1.4.1 - Readme update
* Updated hotkeys in readme
## 1.4.0 - Tags for status
* Now uses line tags to dictate state (improves support for taskpaper)
* Project whitespace fix (thanks @JohannWeging)
* Added shortcut for adding a tag above
## 1.3.0 - Wrapping support
* Updated grammar to support multi-line items
## 1.2.5 - More fixes and cleanup
* Removed some editor deprecations
* Fixed the specs
* General cleanup
## 1.2.4 - Deprecation Fixes
* Updated to fix deprecation notices
## 1.2.2 - ShadowDom Support
* Updated stylesheet selector to support shadow dom editor
## 1.0.1 - Fix updating to new grammar
* Open todo/tasklist files will reload their grammar on settings-change
## 1.0.0 - Overhaul of Grammar
* Grammar now set via code
* Added ability to change markers via settings
## 0.5.0 - Added task cancelling
* Users can now cancel tasks
* Fixed display of context menu to only show on todo files
## 0.4.0 - Added custom date format settings
* Added momentjs back in
* Added custom setting for date format
* Added function to convert dates in-file to format in settings
## 0.3.0 - Removed Momentjs dependency
* Removed momentjs
## 0.2.1 - Changelog
* Finally filled out the changelog
* Fixed some formatting in readme
## 0.2.0 - Publish to Atom
* First publish to atom listing
## 0.1.0 - First Release
* Base syntax highlighting
* Actions for adding new tasks
* Actions for completing tasks
* Actions for archiving
================================================
FILE: LICENSE.md
================================================
Copyright (c) 2014 Christopher Rolfs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
## What's New in 2.0
* Archiving tasks hotkey is now `cmd-shift-a`
* Can convert non-task lines to tasks
* Optimized performance in larger files
* Improved behind-the-scenes code
* Colors improved (also tested in light themes)
* Works with line wrapping
* Status bar shows progress
* See more in the [changelog](https://github.com/irrationalistic/atom-tasks/blob/master/CHANGELOG.md)
# Tasks Package

Special formatting for .todo and .taskpaper files. Allows you to easily add, complete, and archive your tasks.
Adjust the settings to match your ideal style. Change all the markers to '-' to match taskpaper.
Any line that ends with `:` will be considered a header (like `My Things:`)
Add tags to tasks by starting them with an `@`, such as `@important` or setting a value like `@due(tuesday)`.
This uses utf characters, so it is still valid as a plain text document.
You can also set a custom date/time format in the settings. These can be converted in an existing document using the Tasks: Update Timestamp Format.
Based off the awesome sublime text plugin https://github.com/aziz/PlainTasks
## Hotkeys
### Mac
* **cmd-enter:** add a new todo item below the current
* **cmd-shift-enter:** add a new todo item above the current
* **cmd-d:** toggle completion of the task
* **cmd-shift-a:** move all completed tasks to the archive section
* **ctrl-c:** cancel the selected tasks
* **ctrl-s:** add/update timestamp for current task
### PC, Linux
* **ctrl-enter:** add a new todo item below the current
* **ctrl-shift-enter:** add a new todo item above the current
* **ctrl-d:** toggle completion of the task
* **ctrl-shift-a:** move all completed tasks to the archive section
* **alt-c:** cancel the selected tasks
* **ctrl-shift-s:** add/update timestamp for current task
### Other Methods
* **Convert to Task:** Converts a non-task line to a task
* **Update Timestamps:** Attempt to convert cancelled and done tag timestamps to match the settings format
================================================
FILE: demo.todo
================================================
☐ testing
My Tasks:
☐ Implement testing for tasks package
☐ Update styles @normal(tag with value) sounds good
✔ Create TODO package for atom @done(2015-04-09 09:28) @project(Archive)
v2:
✘ Have package order pizza @cancelled(2015-04-09 21:45) @project(v2)
nested:
☐ Another task
================================================
FILE: keymaps/tasks.cson
================================================
# Keybindings require three things to be fully defined: A selector that is
# matched against the focused element, the keystroke and the command to
# execute.
#
# Below is a basic keybinding which registers on all platforms by applying to
# the root workspace element.
# For more detailed documentation see
# https://atom.io/docs/latest/advanced/keymaps
'.platform-darwin atom-workspace atom-text-editor:not(.mini)[data-grammar~="todo"]':
'cmd-enter': 'tasks:add'
'cmd-shift-enter': 'tasks:add-above'
'cmd-d': 'tasks:complete'
'cmd-shift-a': 'tasks:archive'
'ctrl-c': 'tasks:cancel'
'cmd-shift-l': 'tasks:convert-to-task'
'ctrl-s': 'tasks:set-timestamp'
'.platform-win32 atom-workspace atom-text-editor:not(.mini)[data-grammar~="todo"], .platform-linux atom-workspace atom-text-editor:not(.mini)[data-grammar~="todo"]':
'ctrl-enter': 'tasks:add'
'ctrl-shift-enter': 'tasks:add-above'
'ctrl-d': 'tasks:complete'
'ctrl-shift-a': 'tasks:archive'
'alt-c': 'tasks:cancel'
'ctrl-shift-l': 'tasks:convert-to-task'
'ctrl-shift-s': 'tasks:set-timestamp'
================================================
FILE: lib/tasks.coffee
================================================
{Point} = require 'atom'
_ = require 'underscore'
CSON = require 'season'
tasks = require './tasksUtilities'
TaskStatusView = require './views/task-status-view'
touchbar = require './touchbar'
# Store the current settings for the markers
marker = completeMarker = cancelledMarker = archiveSeparator = attributeMarker = ''
module.exports =
###
PLUGIN CONFIGURATION:
###
config:
dateFormat:
type: 'string', default: "YYYY-MM-DD HH:mm"
baseMarker:
type: 'string', default: '☐'
completeMarker:
type: 'string', default: '✔'
cancelledMarker:
type: 'string', default: '✘'
archiveSeparator:
type: 'string', default: '___________________'
attributeMarker:
type: 'string', default: '@'
addTimestampOnConvertToTask:
type: 'boolean', default: false
useTouchbar:
type: 'boolean', default: false
###*
* Activation of the plugin. Should set up
* all listeners and force application of grammar.
* @param {object} state Application state
###
activate: (state) ->
# Get the markers from settings
marker = atom.config.get('tasks.baseMarker')
completeMarker = atom.config.get('tasks.completeMarker')
cancelledMarker = atom.config.get('tasks.cancelledMarker')
archiveSeparator = atom.config.get('tasks.archiveSeparator')
attributeMarker = atom.config.get('tasks.attributeMarker')
# Whenever a marker setting changes, update the grammar
atom.config.observe 'tasks.baseMarker', (val)=>
marker = val; @updateGrammar()
atom.config.observe 'tasks.completeMarker', (val)=>
completeMarker = val; @updateGrammar()
atom.config.observe 'tasks.cancelledMarker', (val)=>
cancelledMarker = val; @updateGrammar()
atom.config.observe 'tasks.archiveSeparator', (val)=>
archiveSeparator = val
atom.config.observe 'tasks.attributeMarker', (val)=>
attributeMarker = val; @updateGrammar()
# Update the grammar when activated
@updateGrammar()
# Set up the command list
atom.commands.add 'atom-text-editor',
"tasks:add": => @newTask()
"tasks:add-above": => @newTask(-1)
"tasks:complete": => @completeTask()
"tasks:archive": => @tasksArchive()
"tasks:update-timestamps": => @tasksUpdateTimestamp()
"tasks:cancel": => @cancelTask()
"tasks:convert-to-task": => @convertToTask()
"tasks:set-timestamp": => @setTimestamp()
config = atom.config.get('tasks')
@useTouchbar = config.useTouchbar
atom.config.onDidChange 'tasks.useTouchbar', ({newValue, oldValue}) =>
@useTouchbar = newValue
if newValue != oldValue
@updateTouchbar()
@activeItemSub = atom.workspace.onDidChangeActivePaneItem =>
@subscribeToActiveTextEditor()
@subscribeToActiveTextEditor()
###*
* Dynamically update the grammar CSON file
* to support user-set values for markers.
###
updateGrammar: ->
# Escape a string
clean = (str)->
for pat in ['\\', '/', '[', ']', '*', '.', '+', '(', ')']
str = str.replace pat, '\\' + pat
str
# Replace given string's markers
rep = (prop)->
str = prop
str = str.replace '☐', clean marker
str = str.replace '✔', clean completeMarker
str = str.replace '✘', clean cancelledMarker
str = str.replace '@', clean attributeMarker
# Load in the grammar manually and do replacement
g = CSON.readFileSync __dirname + '/tasks.cson'
# g.repository.marker.match = rep g.repository.marker.match
g.repository.attribute.match = rep g.repository.attribute.match
g.patterns = g.patterns.map (pattern) ->
pattern.match = rep pattern.match if pattern.match
pattern.begin = rep pattern.begin if pattern.begin
pattern
# first, clear existing grammar
atom.grammars.removeGrammarForScopeName 'source.todo'
# Write updated grammar to file, then update the atom grammar
tasks.writeGrammarSync(g)
newGrammar = atom.grammars.loadGrammarSync tasks.grammarPath
atom.grammars.addGrammar newGrammar
###*
* Helper for handling the status bar
* @param {object} statusBar The statusbar
###
consumeStatusBar: (statusBar) ->
@taskStatus = new TaskStatusView()
@taskStatus.initialize()
@statusBarTile = statusBar.addLeftTile(item: @taskStatus, priority: 100)
getActiveTextEditor: ->
@editor = atom.workspace.getActiveTextEditor()
###*
* Handle deactivation of the plugin. Remove
* all listeners and connections
###
deactivate: ->
@statusBarTile?.destroy()
@statusBarTile = null
@activeItemSub.dispose()
@moveSub?.dispose()
###*
* Watch updates on our editor-in-progress
###
subscribeToActiveTextEditor: ->
@moveSub?.dispose()
@moveSub = @getActiveTextEditor()?.onDidChangeCursorPosition =>
pos = @getActiveTextEditor()?.getCursorBufferPosition()
if pos.row != @lastLine
@lastLine = pos.row
@updateTouchbar()
@updateTouchbar()
###*
* Update our active buttons based on the current line.
###
updateTouchbar: ->
if @useTouchbar && tasks.checkIsTasks()
pt = @editor.getCursorBufferPosition()
config = atom.config.get('tasks')
lineInfo = tasks.parseLine @editor, pt.row, config
lineInfo.wantArchive = @wantArchive
touchbar.update lineInfo, (action) =>
switch action
when "complete" then @completeTask()
when "new" then @newTask()
when "cancel" then @cancelTask()
when "convert" then @convertToTask()
when "archive" then @archiveTasks()
else
touchbar.update({}, null)
###*
* Add a new todo item with the base marker
* @param {number} direction = 1 Defines whether this should
* be above or below the cursor
###
newTask: (direction = 1)->
editor = atom.workspace.getActiveTextEditor()
return if not editor
editor.transact ->
pos = editor.getCursorBufferPosition()
info = tasks.parseLine editor, pos.row, atom.config.get('tasks')
editor.insertNewlineBelow() if direction is 1
editor.insertNewlineAbove() if direction is -1
editor.insertText "#{marker} "
###*
* Helper for completing a task
###
completeTask: ->
editor = atom.workspace.getActiveTextEditor()
return if not editor
selection = editor.getSelectedBufferRanges()
editor.transact ->
tasks.getAllSelectionRows(selection).map (row)->
info = tasks.parseLine editor, row, atom.config.get('tasks')
markerToken = info.marker
doneToken = _.find info.tags, (tag) -> tag.tagName.value is 'done'
if markerToken and not doneToken
# This is a task and isn't already done,
# so calculate the projects this task
# belongs to.
projects = tasks.getProjects editor, row
.map (p)-> tasks.parseProjectName p
.reverse()
# Clear any cancelled information beforehand
tasks.removeTag editor, info, 'cancelled'
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.removeTag editor, info, 'project'
info = tasks.parseLine editor, row, atom.config.get('tasks')
# Add the tag and the projects, if there are any
tasks.addTag editor, row, attributeMarker, 'done', tasks.getFormattedDate()
if projects.length
tasks.addTag editor, row, attributeMarker, 'project', projects.join ' / '
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.setMarker editor, info, completeMarker
else if markerToken and doneToken
# This task was previously completed, so
# just need to clear out the tags
tasks.removeTag editor, info, 'done'
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.removeTag editor, info, 'project'
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.setMarker editor, info, marker
###*
* Helper for cancelling a task
###
cancelTask: ->
editor = atom.workspace.getActiveTextEditor()
return if not editor
selection = editor.getSelectedBufferRanges()
editor.transact ->
tasks.getAllSelectionRows(selection).map (row)->
info = tasks.parseLine editor, row, atom.config.get('tasks')
markerToken = info.marker
cancelledToken = _.find info.tags, (tag) -> tag.tagName.value is 'cancelled'
if markerToken and not cancelledToken
# This is a task and isn't already cancelled,
# so calculate the projects this task
# belongs to.
projects = tasks.getProjects editor, row
.map (p)-> tasks.parseProjectName p
.reverse()
# Clear any done information beforehand
tasks.removeTag editor, info, 'done'
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.removeTag editor, info, 'project'
# Add the tag and the projects, if there are any
tasks.addTag editor, row, attributeMarker, 'cancelled', tasks.getFormattedDate()
if projects.length
tasks.addTag editor, row, attributeMarker, 'project', projects.join ' / '
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.setMarker editor, info, cancelledMarker
else if markerToken and cancelledToken
# This task was previously completed, so
# just need to clear out the tags
tasks.removeTag editor, info, 'cancelled'
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.removeTag editor, info, 'project'
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.setMarker editor, info, marker
###*
* Helper for updating timestamps to match
* the given settings
###
tasksUpdateTimestamp: ->
# Update timestamps to match the current setting (only for tags though)
editor = atom.workspace.getActiveTextEditor()
return if not editor
selection = editor.getSelectedBufferRanges()
editor.transact ->
tasks.getAllSelectionRows(selection).map (row)->
# These tags will receive updated timestamps
# based on existing ones
tagsToUpdate = ['done', 'cancelled', 'timestamp']
for tag in tagsToUpdate
info = tasks.parseLine editor, row, atom.config.get('tasks')
curDateTag = _.find info.tags, (t) -> t.tagName.value is tag
curDate = curDateTag?.tagValue.value
if curDate
tasks.updateTag editor, info, attributeMarker, tag, tasks.getFormattedDate(curDate)
###*
* Helper for converting a non-task
* line to a task
###
convertToTask: ->
editor = atom.workspace.getActiveTextEditor()
return if not editor
selection = editor.getSelectedBufferRanges()
editor.transact =>
tasks.getAllSelectionRows(selection).map (row) =>
info = tasks.parseLine editor, row, atom.config.get('tasks')
if info.type is 'text'
# Only set the marker if this isn't
# already a task or header.
tasks.setMarker editor, info, marker
if atom.config.get('tasks.addTimestampOnConvertToTask')
tasks.addTag editor, row, attributeMarker, 'timestamp', tasks.getFormattedDate()
@updateTouchbar()
###*
* Helper for setting the timestamp on a task. If it exists, remove and
* reset it. If it doesn't exist, add it. This will also update the timestamp
* for tasks that have 'done' or 'cancelled'
###
setTimestamp: ->
editor = atom.workspace.getActiveTextEditor()
return if not editor
selection = editor.getSelectedBufferRanges()
editor.transact ->
tasks.getAllSelectionRows(selection).map (row)->
info = tasks.parseLine editor, row, atom.config.get('tasks')
if info.marker
doneTag = _.find info.tags, (t) -> t.tagName.value is 'done'
cancelledTag = _.find info.tags, (t) -> t.tagName.value is 'cancelled'
timestampTag = _.find info.tags, (t) -> t.tagName.value is 'timestamp'
curDate = tasks.getFormattedDate()
if not doneTag and not cancelledTag and not timestampTag
tasks.addTag editor, row, attributeMarker, 'timestamp', curDate
else
tasks.updateTag editor, info, attributeMarker, 'done', curDate
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.updateTag editor, info, attributeMarker, 'cancelled', curDate
info = tasks.parseLine editor, row, atom.config.get('tasks')
tasks.updateTag editor, info, attributeMarker, 'timestamp', curDate
###*
* Helper for handling the archiving of
* all done and cancelled tasks
###
tasksArchive: ->
editor = atom.workspace.getActiveTextEditor()
return if not editor
editor.transact ->
completedTasks = []
archiveProject = null
insertRow = -1
# 1. Find the archives section, if it exists
editor.buffer.getLines().every (i, ind)->
# if we already found the archive, no need
# to parse any more!
return false if archiveProject
info = tasks.parseLine editor, ind, atom.config.get('tasks')
hasDone = _.some info.tags, (t) -> t.tagName.value is 'done'
hasCancelled = _.some info.tags, (t) -> t.tagName.value is 'cancelled'
hasArchive = info.project is 'Archive'
el =
lineNumber: ind
line: i
archiveProject = el if hasArchive
completedTasks.push el if hasDone or hasCancelled
true
# 2. I have a list of all completed tasks,
# as well as where the archive exists, if it does
if not archiveProject
# no archive? create it!
archiveText = """
#{archiveSeparator}
Archive:
"""
# Before adding the final archive section,
# we should clear out the empty lines at
# the end of the file.
for line, i in editor.buffer.getLines() by -1
if editor.buffer.isRowBlank i
# remove the line
editor.buffer.deleteRow i
else
break
# add to the end of the file
newRange = editor.buffer.append archiveText
insertRow = newRange.end.row
else
insertRow = archiveProject.lineNumber + 1
# 3. Archive insertion point is ready! Let's
# start copying down the completed items.
completedTasks.reverse()
insertPoint = new Point insertRow, 0
indentation = editor.buildIndentString 1
completedTasks.forEach (i)->
editor.buffer.insert insertPoint, "#{indentation}#{i.line.trim()}\n"
# 4. Copy is completed, start deleting the
# copied items
completedTasks.forEach (i)->
editor.buffer.deleteRow i.lineNumber
================================================
FILE: lib/tasks.cson
================================================
'fileTypes': [
'todo'
'taskpaper'
]
'scopeName': 'source.todo'
'name': 'Tasks'
'patterns': [
{
'match': '^([\\s]*)(.*):$'
'name': 'control.tasks.header.${2:/downcase}'
'captures': '2': 'name': 'control.tasks.header-title'
}
{
'begin': '^([\\s]*)(✔)(?=.*@done)'
'end': '$'
'name': 'tasks.text.done'
'beginCaptures':
'2': 'name': 'keyword.tasks.marker'
'patterns': [
{'include': '#attribute'}
]
}
{
'begin': '^([\\s]*)(✘)(?=.*@cancelled)'
'end': '$'
'name': 'tasks.text.cancelled'
'beginCaptures':
'2': 'name': 'keyword.tasks.marker'
'patterns': [
{'include': '#attribute'}
]
}
{
'begin': '^([\\s]*)(☐)'
'end': '$'
'name': 'tasks.text'
'beginCaptures':
'2': 'name': 'keyword.tasks.marker'
'patterns': [
{'include': '#attribute'},
{'include': 'text.md'}
{'include': 'text.hyperlink'}
]
}
]
'repository':
'attribute':
'match': '@([\\w]+)(?:\\((.*?)\\))?'
'name': 'tasks.attribute.$1'
'captures':
'1': 'name': 'tasks.attribute-name'
'2': 'name': 'tasks.attribute-value'
================================================
FILE: lib/tasksUtilities.coffee
================================================
{Point, Range} = require 'atom'
_ = require 'underscore'
CSON = require 'season'
moment = require 'moment'
path = require 'path'
# ATTRIBUTE_RX = /( ?)(@[ ]?(([\w]+)(\((.*?)\))?))/gi
module.exports =
markerSelector: 'keyword.tasks.marker'
doneSelector: 'tasks.text.done'
cancelledSelector: 'tasks.text.cancelled'
archiveSelector: 'control.tasks.header.archive'
headerSelector: 'control.tasks.header-title'
grammarPath: path.join process.env.ATOM_HOME, 'TasksGrammar.cson'
# Escape a string
cleanRegex: (str)->
for pat in ['\\', '/', '[', ']', '*', '.', '+', '(', ')']
str = str.replace pat, '\\' + pat
str
###*
* Write a new grammar file to disk so that it can be loaded in
* dynamically.
* @param {Object} grammarObj The object to write to disk representing
* the grammar content as CSON
* @return void
###
writeGrammarSync: (grammarObj) ->
CSON.writeFileSync @grammarPath, grammarObj
parseLine: (editor, lineNumber, config) ->
whiteRx = /^\s*/
projectRx = /^\s*(.*):$/
baseMarker = @cleanRegex config.baseMarker
completeMarker = @cleanRegex config.completeMarker
cancelledMarker = @cleanRegex config.cancelledMarker
taskRx = new RegExp "^(\\s*)(#{baseMarker}|#{completeMarker}|#{cancelledMarker})(.*)$"
line = editor.buffer.lineForRow lineNumber
indentation = editor.indentationForBufferRow lineNumber
result =
lineNumber: lineNumber
line: line
indentation: indentation
firstNonWhitespaceIndex: line.match(whiteRx)[0].length
type = 'text'
if projectRx.test line
type = 'project'
match = line.match projectRx
result.project = match[1]
else if taskRx.test line
type = 'task'
match = line.match taskRx
result.marker =
value: match[2]
range: new Range new Point(lineNumber, match[1].length), new Point(lineNumber, match[1].length + match[2].length)
result.text = match[3].trim()
result.tags = @getAllTags editor, lineNumber, config.attributeMarker
result.type = type
return result
###*
* Get all the tags on a given line
* @param {TextEditor} editor Editor to use
* @param {Number} lineNumber Number of line
###
getAllTags: (editor, lineNumber, attributeMarker)->
tags = []
# lines = editor.displayBuffer.tokenizedBuffer.tokenizedLines
# checkLine = lines[lineNumber]
checkLine = editor.buffer.lineForRow lineNumber
attributeRX = new RegExp "( ?)(\\#{attributeMarker}[ ]?(([\\w]+)(\\((.*?[^\\\\])\\))?))", 'gi'
while match = attributeRX.exec checkLine
sPt = new Point lineNumber, match.index
ePt = new Point lineNumber, match.index + match[0].length
nameStart = new Point(
lineNumber,
match.index + match[0].indexOf match[4]
)
nameEnd = new Point(
lineNumber,
match.index + match[0].indexOf(match[4]) + match[4].length
)
if match[6]
valueStart = new Point(
lineNumber,
match.index + match[0].indexOf match[6]
)
valueEnd = new Point(
lineNumber,
match.index + match[0].indexOf(match[6]) + match[6].length
)
tags.push
tagName:
value: match[4]
range: new Range nameStart, nameEnd
tagValue:
value: match[6]
range: new Range valueStart, valueEnd
range: new Range sPt, ePt
tags
###*
* Get a specific tag from the given line
* @param {TextEditor} editor Editor to use
* @param {Number} lineNumber Line number to use
* @param {String} tagName Tag to find
* @param {String} attributeMarker Marker character in use
###
getTag: (editor, lineNumber, tagName, attributeMarker)->
tags = @getAllTags editor, lineNumber, attributeMarker
_.find tags, (t)->t.tagName.value is tagName
###*
* Helper for adding a tag/value to a given line
* @param {TextEditor} editor Editor to use
* @param {Number} lineNumber Line number to use
* @param {String} attributeMarker Marker being used for attributes
* @param {String} tagName Name of tag
* @param {String} tagValue Value of tag (optional)
###
addTag: (editor, lineNumber, attributeMarker, tagName, tagValue)->
point = new Point lineNumber, editor.buffer.lineLengthForRow lineNumber
if tagValue
safeTagValue = @escapeTagValue tagValue
editor.buffer.insert point, " #{attributeMarker}#{tagName}(#{safeTagValue})"
else
editor.buffer.insert point, " #{attributeMarker}#{tagName}"
escapeTagValue: (tagValue) ->
tagValue.replace(/\(/g, "\\(").replace(/\)/g, "\\)")
###*
* Helper for removing a tag by name
* @param {TextEditor} editor Editor to use
* @param {Number} lineNumber Line number to remove from
* @param {String} tagName Tag name to remove
* @param {String} attributeMarker Marker character in use
###
removeTag: (editor, info, tagName)->
match = _.find info.tags, (i)->i.tagName.value is tagName
editor.buffer.delete match.range if match
###*
* Helper for updating the value of a tag
* @param {TextEditor} editor Editor to use
* @param {Number} lineNumber Line number to update on
* @param {String} attributeMarker Marker character in use
* @param {String} tagName Tag name to update value of
* @param {String} newTagValue New value of tag (optional).
* Leave undefined to remove value
###
updateTag: (editor, info, attributeMarker, tagName, newTagValue)->
tag = _.find info.tags, (t) -> t.tagName.value is tagName
return if not tag
if newTagValue
if tag.tagValue.range.isEmpty()
pt = tag.tagName.range.end
editor.buffer.insert pt, "(#{newTagValue})"
else
editor.buffer.setTextInRange tag.tagValue.range, newTagValue
else
if not tag.tagValue.range.isEmpty()
tag.tagValue.range.start.column--
tag.tagValue.range.end.column++
editor.buffer.delete tag.tagValue.range
###*
* Find the token on the line given a css-like selector
* @param {Array} tokens Array of tokens to look through
* @param {String} selector CSS-like selector to search for
###
getToken: (tokens, selector)->
for token in tokens
return token if selector in token.scopes
null
###*
* Given a token search string, find all
* lines in the given editor that match
* @param {TextEditor} editor Editor to use
* @param {String} toFind CSS-like selector to search for
###
getLinesByToken: (editor, toFind)->
editor.tokenizedBuffer.tokenizedLines.filter (i)=>
@getToken i.tokens, toFind
###*
* Helper for finding all parent nodes of this line
* that are projects
* @param {TextEditor} editor Editor to use
* @param {Number} lineNumber Line number to start at
###
getProjects: (editor, lineNumber)->
lines = editor.tokenizedBuffer.tokenizedLines
projects = []
curHeaderLevel = editor.indentationForBufferRow(lineNumber)
return projects if lineNumber is 0
for row in [lineNumber-1..0]
curLine = lines[row]
if editor.indentationForBufferRow(row) < curHeaderLevel
if @getToken curLine.tokens, @headerSelector
projects.push curLine
curHeaderLevel = editor.indentationForBufferRow(row)
rowIsZero = editor.indentationForBufferRow(row) is 0
rowIsEmpty = editor.isBufferRowBlank(row)
break if rowIsZero and not rowIsEmpty
projects
###*
* Given a project line, parse out just the name
* @param {TokenizedLine} line TokenizedLine to parse
###
parseProjectName: (line)->
match = @getToken line.tokens, @headerSelector
match.value
###*
* Helper for getting the rows of a selection,
* which can be made up of an array of ranges.
* @param {Array} selection Array of ranges
###
getAllSelectionRows: (selection)->
_.flatten selection.map (s)->s.getRows()
###*
* Helper for getting the date based on given settings
* @return {Date/String} Date or date string to use
###
getFormattedDate: (date = Date.now())->
moment(date).format(atom.config.get('tasks.dateFormat'))
###*
* Helper for setting the marker of a given line
* @param {TextEditor} editor Editor to use
* @param {Number} lineNumber Line number to use
* @param {String} markerText New marker to set
###
setMarker: (editor, info, markerText)->
# given some line, change the marker
# if it exists, or add one if it doesn't
if info.marker
editor.buffer.setTextInRange info.marker.range, markerText
else
# need to insert the marker
pt = new Point info.lineNumber, info.firstNonWhitespaceIndex
editor.buffer.insert pt, markerText + ' '
###*
* Determine if the currently-edited buffer is a task document
###
checkIsTasks: ->
editor = atom.workspace.getActiveTextEditor()
return editor?.getGrammar().name is 'Tasks'
================================================
FILE: lib/touchbar.coffee
================================================
tasks = require './tasksUtilities'
{TouchBar} = require('remote')
{TouchBarButton, TouchBarSpacer} = TouchBar
module.exports =
update: (info, callback) ->
return if not TouchBar
window = atom.getCurrentWindow()
if not info.type || not tasks.checkIsTasks()
window.setTouchBar(null)
return
buttons = []
config = atom.config.get('tasks')
isTask = info.type == 'task'
if isTask
completed = info.marker.value in [config.completeMarker, config.cancelledMarker]
buttons.push @callbackButton(config.baseMarker, "New", callback, '#5293d8')
buttons.push new TouchBarSpacer({size: 'small'})
if isTask && ! completed
buttons.push @callbackButton(config.completeMarker, "Complete", callback, '#45A815')
buttons.push new TouchBarSpacer({size: 'small'})
buttons.push @callbackButton(config.cancelledMarker, "Cancel", callback, '#CD8E00')
buttons.push new TouchBarSpacer({size: 'small'})
if ! isTask && /\S/.test(info.line)
buttons.push @callbackButton(config.baseMarker, "Convert", callback)
buttons.push new TouchBarSpacer({size: 'small'})
touchBar = new TouchBar({items: buttons})
window.setTouchBar(touchBar)
callbackButton: (icon, command, callback, bgcolor) ->
opts = {
label: "#{icon} #{command}",
click: () =>
callback(command.toLowerCase())
}
if bgcolor
opts.backgroundColor = bgcolor
return new TouchBarButton(opts)
================================================
FILE: lib/views/task-status-view.coffee
================================================
tasks = require '../tasksUtilities'
_ = require 'underscore'
class TaskStatusView extends HTMLElement
initialize: ->
@classList.add('task-status', 'inline-block')
@style.display = 'none'
@activeItemSub = atom.workspace.onDidChangeActivePaneItem =>
@subscribeToActiveTextEditor()
@subscribeToActiveTextEditor()
destroy: ->
@activeItemSub.dispose()
@changeSub?.dispose()
@tokenizeSub?.dispose()
subscribeToActiveTextEditor: ->
@changeSub?.dispose()
@changeSub = @getActiveTextEditor()?.onDidStopChanging =>
@updateStatus()
@tokenizeSub?.dispose()
@tokenizeSub = @getActiveTextEditor()?.tokenizedBuffer
.onDidTokenize => @updateStatus()
@updateStatus()
getActiveTextEditor: ->
@editor = atom.workspace.getActiveTextEditor()
checkIsTasks: ->
if tasks.checkIsTasks()
@style.display = ''
return true
@style.display = 'none'
false
updateStatus: ->
if @checkIsTasks()
tokenizedLines = @editor.tokenizedBuffer.tokenizedLines
info = _.countBy tokenizedLines, (line)->
return 'text' if not line
hasMarker = tasks.getToken line.tokens, tasks.markerSelector
hasDone = tasks.getToken line.tokens, tasks.doneSelector
hasCancelled = tasks.getToken line.tokens, tasks.cancelledSelector
hasProject = tasks.getToken line.tokens, tasks.headerSelector
return 'project' if hasProject
return 'done' if hasDone
return 'cancelled' if hasCancelled
return 'task' if hasMarker
return 'text'
_.defaults info,
done: 0, cancelled: 0
project: 0, task: 0
text: 0
completed = info.done + info.cancelled
total = completed + info.task
completed = '-' if isNaN completed
total = '-' if isNaN total
@textContent = "(#{completed}/#{total})"
module.exports = document.registerElement 'status-bar-tasks',
prototype: TaskStatusView.prototype, extends: 'div'
================================================
FILE: menus/tasks.cson
================================================
'context-menu':
'atom-text-editor[data-grammar~="todo"]': [
{'type': 'separator'}
{
'label': 'Add Task Below',
'command': 'tasks:add'
}
{
'label': 'Add Task Above',
'command': 'tasks:add-above'
}
{
'label': 'Complete Task',
'command': 'tasks:complete'
}
{
'label': 'Cancel Task',
'command': 'tasks:cancel'
}
{
'label': 'Archive Tasks',
'command': 'tasks:archive'
}
{
'label': 'Convert to Task',
'command': 'tasks:convert-to-task'
}
{
'label': 'Update Timestamp Format',
'command': 'tasks:update-timestamps'
}
{
'label': 'Add/Update Current Timestamp',
'command': 'tasks:set-timestamp'
}
{'type': 'separator'}
]
================================================
FILE: package.json
================================================
{
"name": "tasks",
"main": "./lib/tasks",
"version": "2.10.1",
"description": "Manage your todo lists",
"keywords": [
"tasks",
"todo",
"productivity",
"utilities",
"taskpaper"
],
"repository": "https://github.com/irrationalistic/atom-tasks",
"license": "MIT",
"engines": {
"atom": ">= 1.13"
},
"dependencies": {
"moment": "~2.11.2",
"underscore": "^1.8.3",
"season": "~6.0.2"
},
"consumedServices": {
"status-bar": {
"versions": {
"^1.0.0": "consumeStatusBar"
}
}
}
}
================================================
FILE: project.todo
================================================
v3:
☐ Add more test coverage for utilities
☐ Export functionality as a service?
☐ Add pull-request to symbols view package
☐ Add line-level decorations for given tags (#22)
☐ Plan for query language system (#19)
___________________
Archive:
✔ Make value optional in addTag @done(2015-04-12 22:14) @project(v2)
✔ Make value optional in updateTag (also support not having a value previously) @done(2015-04-12 22:14) @project(v2)
✔ Clean up tasks.coffee file @done(2015-04-12 11:21) @project(v2)
✔ Fix for projects on own line @done(2015-04-11 17:20) @project(v2)
✔ Add support for complex markers (like [ ] and [x]) @done(2015-04-11 16:56) @project(v2)
✔ Support markers with different sizes @done(2015-04-11 16:56) @project(v2)
✔ Add package keywords @done(2015-04-11 16:28) @project(v2)
✔ Add progress to status bar @done(2015-04-11 16:28) @project(v3)
✔ Improving token matching @done(2015-04-11 10:53) @project(v2)
✔ Update menu @done(2015-04-10 21:55) @project(v2)
✔ Add benchmark @done(2015-04-10 21:52) @project(v2)
✔ Fix up tests @done(2015-04-10 21:35) @project(v2)
✔ Archive should minimize spacing on remaining lines (no more than one line away from last real line) @done(2015-04-10 12:21) @project(v2)
✔ Update readme @done(2015-04-10 11:37) @project(v2)
✘ Add method for updating all markers to new values @cancelled(2015-04-09 22:18) @project(v2)
✘ Fix awkward coloring in minimap @cancelled(2015-04-09 22:07) @project(v2)
✔ Clear out unnecessary files @done(2015-04-09 22:06) @project(v2)
✔ Commands need spaces in name @done(2015-04-09 22:04) @project(v2)
✘ Prevent duplicate adding task attribute @cancelled(2015-04-09 22:00) @project(v2)
✘ Better time printing when updating timestamp @cancelled(2015-04-09 22:00) @project(v2)
✔ Don't add project tag to things without projects when completed @done(2015-04-09 21:47) @project(v2)
✔ Cancelling a done task or vice-versa @done(2015-04-09 21:45) @project(v2)
✔ Test with light syntax theme @done(2015-04-09 21:42) @project(v2)
✔ Support for wrapping @done(2015-04-09 21:40) @project(v2)
✔ Updating marker helper @done(2015-04-09 16:39) @project(v2)
✔ Converting to task from non-task @done(2015-04-09 09:46) @project(v2)
✔ Improve archiving tasks @done(2015-04-09 21:19) @project(v2)
✔ Converting a task should ignore project lines @done(2015-04-09 10:09) @project(v2)
✔ Update timestamps should work on tasks without timestamp @done(2015-04-09 09:28) @project(v2)
✔ Update timestamps should work on cancelled items @done(2015-04-09 09:28) @project(v2)
✔ Update new task method @done(2015-04-09 15:52) @project(v2)
✔ Support non-indented tasks @done(2015-04-09 15:53) @project(v2)
================================================
FILE: settings/tasks.cson
================================================
'.source.todo, .source.taskpaper':
'editor':
'autoIndentOnPaste': false
'increaseIndentPattern': '^.*:$'
================================================
FILE: spec/benchmark.todo
================================================
Project 0:
☐ test 1
☐ test 2
☐ test 3
☐ test 4
☐ test 5
☐ test 6
☐ test 7
☐ test 8
☐ test 9
☐ test 10
☐ test 11
Project 12:
☐ test 13
☐ test 14
☐ test 15
☐ test 16
☐ test 17
☐ test 18
☐ test 19
☐ test 20
☐ test 21
Project 22:
☐ test 23
☐ test 24
☐ test 25
☐ test 26
☐ test 27
Project 28:
☐ test 29
☐ test 30
☐ test 31
☐ test 32
☐ test 33
☐ test 34
☐ test 35
☐ test 36
☐ test 37
☐ test 38
☐ test 39
☐ test 40
☐ test 41
☐ test 42
☐ test 43
☐ test 44
☐ test 45
Project 46:
☐ test 47
☐ test 48
☐ test 49
☐ test 50
☐ test 51
☐ test 52
☐ test 53
☐ test 54
☐ test 55
☐ test 56
☐ test 57
☐ test 58
☐ test 59
☐ test 60
Project 61:
☐ test 62
☐ test 63
☐ test 64
☐ test 65
☐ test 66
☐ test 67
Project 68:
☐ test 69
☐ test 70
☐ test 71
☐ test 72
☐ test 73
☐ test 74
Project 75:
☐ test 76
☐ test 77
☐ test 78
Project 79:
☐ test 80
☐ test 81
☐ test 82
☐ test 83
☐ test 84
☐ test 85
☐ test 86
☐ test 87
☐ test 88
Project 89:
☐ test 90
☐ test 91
☐ test 92
☐ test 93
☐ test 94
☐ test 95
☐ test 96
Project 97:
☐ test 98
☐ test 99
☐ test 100
☐ test 101
☐ test 102
☐ test 103
☐ test 104
☐ test 105
☐ test 106
☐ test 107
☐ test 108
☐ test 109
☐ test 110
☐ test 111
☐ test 112
☐ test 113
☐ test 114
Project 115:
☐ test 116
☐ test 117
☐ test 118
☐ test 119
☐ test 120
☐ test 121
Project 122:
☐ test 123
☐ test 124
☐ test 125
☐ test 126
☐ test 127
☐ test 128
☐ test 129
☐ test 130
☐ test 131
☐ test 132
☐ test 133
☐ test 134
☐ test 135
☐ test 136
☐ test 137
Project 138:
☐ test 139
☐ test 140
☐ test 141
☐ test 142
☐ test 143
☐ test 144
☐ test 145
☐ test 146
☐ test 147
☐ test 148
Project 149:
☐ test 150
☐ test 151
☐ test 152
☐ test 153
☐ test 154
☐ test 155
☐ test 156
☐ test 157
Project 158:
☐ test 159
☐ test 160
☐ test 161
☐ test 162
☐ test 163
☐ test 164
☐ test 165
☐ test 166
☐ test 167
☐ test 168
☐ test 169
☐ test 170
☐ test 171
☐ test 172
☐ test 173
☐ test 174
☐ test 175
☐ test 176
☐ test 177
☐ test 178
☐ test 179
☐ test 180
☐ test 181
☐ test 182
☐ test 183
☐ test 184
Project 185:
☐ test 186
☐ test 187
☐ test 188
☐ test 189
☐ test 190
Project 191:
☐ test 192
☐ test 193
☐ test 194
Project 195:
☐ test 196
☐ test 197
☐ test 198
☐ test 199
☐ test 200
☐ test 201
☐ test 202
☐ test 203
Project 204:
☐ test 205
☐ test 206
☐ test 207
☐ test 208
Project 209:
☐ test 210
☐ test 211
☐ test 212
☐ test 213
☐ test 214
☐ test 215
☐ test 216
Project 217:
☐ test 218
☐ test 219
Project 220:
☐ test 221
☐ test 222
Project 223:
☐ test 224
☐ test 225
☐ test 226
Project 227:
☐ test 228
☐ test 229
☐ test 230
☐ test 231
☐ test 232
☐ test 233
☐ test 234
☐ test 235
☐ test 236
☐ test 237
☐ test 238
☐ test 239
☐ test 240
☐ test 241
☐ test 242
☐ test 243
☐ test 244
☐ test 245
Project 246:
☐ test 247
☐ test 248
☐ test 249
Project 250:
☐ test 251
☐ test 252
☐ test 253
☐ test 254
☐ test 255
☐ test 256
☐ test 257
☐ test 258
☐ test 259
☐ test 260
Project 261:
☐ test 262
☐ test 263
☐ test 264
☐ test 265
☐ test 266
☐ test 267
☐ test 268
☐ test 269
☐ test 270
☐ test 271
☐ test 272
Project 273:
☐ test 274
☐ test 275
☐ test 276
☐ test 277
☐ test 278
☐ test 279
☐ test 280
☐ test 281
☐ test 282
Project 283:
☐ test 284
☐ test 285
Project 286:
☐ test 287
Project 288:
☐ test 289
☐ test 290
☐ test 291
☐ test 292
☐ test 293
☐ test 294
☐ test 295
Project 296:
☐ test 297
☐ test 298
☐ test 299
☐ test 300
☐ test 301
☐ test 302
☐ test 303
Project 304:
☐ test 305
☐ test 306
☐ test 307
☐ test 308
☐ test 309
☐ test 310
☐ test 311
☐ test 312
☐ test 313
☐ test 314
☐ test 315
☐ test 316
Project 317:
☐ test 318
☐ test 319
☐ test 320
☐ test 321
☐ test 322
☐ test 323
Project 324:
☐ test 325
☐ test 326
Project 327:
☐ test 328
☐ test 329
☐ test 330
☐ test 331
☐ test 332
Project 333:
☐ test 334
☐ test 335
☐ test 336
☐ test 337
☐ test 338
☐ test 339
☐ test 340
☐ test 341
☐ test 342
☐ test 343
Project 344:
☐ test 345
☐ test 346
Project 347:
☐ test 348
Project 349:
☐ test 350
☐ test 351
☐ test 352
☐ test 353
Project 354:
☐ test 355
☐ test 356
☐ test 357
☐ test 358
☐ test 359
☐ test 360
☐ test 361
☐ test 362
☐ test 363
Project 364:
☐ test 365
☐ test 366
☐ test 367
Project 368:
Project 369:
☐ test 370
☐ test 371
☐ test 372
☐ test 373
☐ test 374
☐ test 375
☐ test 376
☐ test 377
☐ test 378
☐ test 379
☐ test 380
☐ test 381
☐ test 382
☐ test 383
☐ test 384
☐ test 385
☐ test 386
☐ test 387
☐ test 388
☐ test 389
Project 390:
☐ test 391
☐ test 392
☐ test 393
☐ test 394
☐ test 395
☐ test 396
☐ test 397
☐ test 398
☐ test 399
Project 400:
☐ test 401
Project 402:
Project 403:
☐ test 404
☐ test 405
☐ test 406
Project 407:
☐ test 408
☐ test 409
☐ test 410
☐ test 411
☐ test 412
☐ test 413
☐ test 414
☐ test 415
☐ test 416
Project 417:
☐ test 418
☐ test 419
☐ test 420
☐ test 421
☐ test 422
Project 423:
☐ test 424
☐ test 425
☐ test 426
☐ test 427
☐ test 428
☐ test 429
☐ test 430
☐ test 431
☐ test 432
☐ test 433
☐ test 434
☐ test 435
☐ test 436
☐ test 437
Project 438:
☐ test 439
☐ test 440
☐ test 441
☐ test 442
☐ test 443
☐ test 444
☐ test 445
Project 446:
☐ test 447
Project 448:
☐ test 449
☐ test 450
☐ test 451
☐ test 452
☐ test 453
☐ test 454
☐ test 455
☐ test 456
☐ test 457
☐ test 458
☐ test 459
☐ test 460
☐ test 461
☐ test 462
☐ test 463
☐ test 464
☐ test 465
☐ test 466
Project 467:
☐ test 468
☐ test 469
Project 470:
☐ test 471
☐ test 472
☐ test 473
☐ test 474
☐ test 475
Project 476:
☐ test 477
☐ test 478
☐ test 479
☐ test 480
☐ test 481
☐ test 482
☐ test 483
☐ test 484
☐ test 485
☐ test 486
☐ test 487
☐ test 488
☐ test 489
☐ test 490
☐ test 491
☐ test 492
☐ test 493
☐ test 494
☐ test 495
☐ test 496
☐ test 497
☐ test 498
☐ test 499
☐ test 500
☐ test 501
☐ test 502
☐ test 503
Project 504:
☐ test 505
☐ test 506
☐ test 507
☐ test 508
☐ test 509
☐ test 510
☐ test 511
☐ test 512
☐ test 513
☐ test 514
☐ test 515
☐ test 516
☐ test 517
☐ test 518
Project 519:
☐ test 520
☐ test 521
☐ test 522
☐ test 523
Project 524:
☐ test 525
☐ test 526
☐ test 527
☐ test 528
☐ test 529
Project 530:
☐ test 531
☐ test 532
☐ test 533
☐ test 534
☐ test 535
☐ test 536
☐ test 537
☐ test 538
☐ test 539
☐ test 540
☐ test 541
☐ test 542
☐ test 543
Project 544:
☐ test 545
Project 546:
☐ test 547
☐ test 548
☐ test 549
☐ test 550
☐ test 551
☐ test 552
☐ test 553
Project 554:
Project 555:
☐ test 556
☐ test 557
☐ test 558
☐ test 559
☐ test 560
☐ test 561
☐ test 562
☐ test 563
Project 564:
☐ test 565
☐ test 566
☐ test 567
☐ test 568
☐ test 569
☐ test 570
☐ test 571
☐ test 572
☐ test 573
☐ test 574
Project 575:
Project 576:
☐ test 577
☐ test 578
☐ test 579
☐ test 580
☐ test 581
☐ test 582
☐ test 583
Project 584:
☐ test 585
☐ test 586
☐ test 587
☐ test 588
☐ test 589
☐ test 590
☐ test 591
Project 592:
☐ test 593
☐ test 594
☐ test 595
☐ test 596
☐ test 597
☐ test 598
☐ test 599
☐ test 600
☐ test 601
☐ test 602
Project 603:
☐ test 604
☐ test 605
☐ test 606
☐ test 607
☐ test 608
☐ test 609
☐ test 610
☐ test 611
☐ test 612
☐ test 613
☐ test 614
☐ test 615
☐ test 616
☐ test 617
☐ test 618
☐ test 619
☐ test 620
☐ test 621
Project 622:
☐ test 623
☐ test 624
☐ test 625
☐ test 626
☐ test 627
☐ test 628
☐ test 629
☐ test 630
☐ test 631
☐ test 632
☐ test 633
☐ test 634
☐ test 635
☐ test 636
☐ test 637
☐ test 638
☐ test 639
☐ test 640
☐ test 641
☐ test 642
☐ test 643
☐ test 644
☐ test 645
Project 646:
☐ test 647
☐ test 648
☐ test 649
☐ test 650
☐ test 651
☐ test 652
☐ test 653
☐ test 654
☐ test 655
☐ test 656
☐ test 657
☐ test 658
☐ test 659
Project 660:
☐ test 661
☐ test 662
☐ test 663
Project 664:
☐ test 665
☐ test 666
☐ test 667
☐ test 668
☐ test 669
Project 670:
☐ test 671
☐ test 672
☐ test 673
☐ test 674
☐ test 675
☐ test 676
☐ test 677
☐ test 678
☐ test 679
☐ test 680
☐ test 681
☐ test 682
☐ test 683
☐ test 684
Project 685:
☐ test 686
☐ test 687
☐ test 688
☐ test 689
☐ test 690
☐ test 691
☐ test 692
☐ test 693
Project 694:
☐ test 695
☐ test 696
☐ test 697
☐ test 698
☐ test 699
☐ test 700
☐ test 701
☐ test 702
☐ test 703
Project 704:
☐ test 705
☐ test 706
☐ test 707
☐ test 708
☐ test 709
☐ test 710
☐ test 711
☐ test 712
☐ test 713
☐ test 714
☐ test 715
☐ test 716
☐ test 717
☐ test 718
Project 719:
☐ test 720
☐ test 721
☐ test 722
Project 723:
☐ test 724
☐ test 725
☐ test 726
☐ test 727
☐ test 728
☐ test 729
☐ test 730
☐ test 731
☐ test 732
☐ test 733
☐ test 734
☐ test 735
☐ test 736
☐ test 737
☐ test 738
☐ test 739
☐ test 740
☐ test 741
☐ test 742
Project 743:
☐ test 744
☐ test 745
☐ test 746
☐ test 747
☐ test 748
☐ test 749
☐ test 750
☐ test 751
☐ test 752
☐ test 753
Project 754:
☐ test 755
☐ test 756
☐ test 757
☐ test 758
☐ test 759
☐ test 760
☐ test 761
☐ test 762
☐ test 763
☐ test 764
☐ test 765
☐ test 766
☐ test 767
☐ test 768
☐ test 769
☐ test 770
☐ test 771
☐ test 772
☐ test 773
☐ test 774
☐ test 775
☐ test 776
☐ test 777
☐ test 778
☐ test 779
☐ test 780
☐ test 781
☐ test 782
Project 783:
☐ test 784
☐ test 785
☐ test 786
☐ test 787
☐ test 788
☐ test 789
☐ test 790
☐ test 791
☐ test 792
☐ test 793
☐ test 794
☐ test 795
Project 796:
☐ test 797
☐ test 798
☐ test 799
☐ test 800
☐ test 801
☐ test 802
☐ test 803
☐ test 804
☐ test 805
☐ test 806
☐ test 807
☐ test 808
☐ test 809
☐ test 810
Project 811:
Project 812:
Project 813:
☐ test 814
☐ test 815
Project 816:
Project 817:
☐ test 818
☐ test 819
Project 820:
☐ test 821
☐ test 822
Project 823:
☐ test 824
☐ test 825
☐ test 826
☐ test 827
☐ test 828
☐ test 829
☐ test 830
☐ test 831
☐ test 832
☐ test 833
☐ test 834
☐ test 835
Project 836:
Project 837:
Project 838:
☐ test 839
☐ test 840
☐ test 841
☐ test 842
☐ test 843
☐ test 844
Project 845:
☐ test 846
☐ test 847
Project 848:
☐ test 849
☐ test 850
☐ test 851
☐ test 852
☐ test 853
☐ test 854
☐ test 855
☐ test 856
Project 857:
☐ test 858
☐ test 859
☐ test 860
☐ test 861
☐ test 862
☐ test 863
☐ test 864
☐ test 865
☐ test 866
☐ test 867
☐ test 868
☐ test 869
☐ test 870
☐ test 871
☐ test 872
☐ test 873
☐ test 874
☐ test 875
☐ test 876
☐ test 877
☐ test 878
☐ test 879
☐ test 880
Project 881:
☐ test 882
☐ test 883
☐ test 884
☐ test 885
☐ test 886
☐ test 887
☐ test 888
☐ test 889
Project 890:
☐ test 891
☐ test 892
☐ test 893
☐ test 894
☐ test 895
☐ test 896
☐ test 897
☐ test 898
☐ test 899
☐ test 900
☐ test 901
☐ test 902
☐ test 903
☐ test 904
☐ test 905
☐ test 906
☐ test 907
☐ test 908
☐ test 909
☐ test 910
☐ test 911
☐ test 912
☐ test 913
☐ test 914
☐ test 915
☐ test 916
☐ test 917
☐ test 918
☐ test 919
Project 920:
☐ test 921
☐ test 922
☐ test 923
☐ test 924
☐ test 925
☐ test 926
☐ test 927
☐ test 928
☐ test 929
☐ test 930
☐ test 931
Project 932:
☐ test 933
☐ test 934
☐ test 935
☐ test 936
☐ test 937
☐ test 938
☐ test 939
☐ test 940
☐ test 941
☐ test 942
☐ test 943
☐ test 944
☐ test 945
☐ test 946
☐ test 947
☐ test 948
☐ test 949
☐ test 950
☐ test 951
☐ test 952
☐ test 953
☐ test 954
☐ test 955
☐ test 956
☐ test 957
☐ test 958
Project 959:
☐ test 960
☐ test 961
☐ test 962
☐ test 963
☐ test 964
☐ test 965
☐ test 966
☐ test 967
☐ test 968
☐ test 969
☐ test 970
Project 971:
☐ test 972
☐ test 973
☐ test 974
☐ test 975
☐ test 976
☐ test 977
☐ test 978
☐ test 979
☐ test 980
☐ test 981
☐ test 982
☐ test 983
Project 984:
☐ test 985
☐ test 986
☐ test 987
☐ test 988
☐ test 989
☐ test 990
☐ test 991
☐ test 992
Project 993:
☐ test 994
☐ test 995
☐ test 996
☐ test 997
☐ test 998
☐ test 999
☐ test 1000
================================================
FILE: spec/complexMarkers.todo
================================================
Test:
[ ] First task @tag1
[ ] Second task
plain text, non-task
[ ] Another task
================================================
FILE: spec/sample.taskpaper
================================================
Yard:
- Rake leaves
- Put away hose @tag1 and something else @tag2
- Clear garden
Groceries:
- Milk
- Eggs
- Lettuce
================================================
FILE: spec/tasks-spec.coffee
================================================
path = require 'path'
Tasks = require '../lib/tasks'
tasksUtilities = require '../lib/tasksUtilities'
[editor, buffer, grammar, workspaceElement] = []
baseTokens = ['source.todo', 'tasks.text']
doneTokens = ['source.todo', 'tasks.text.done']
cancelledTokens = ['source.todo', 'tasks.text.cancelled']
nowStamp = ''
describe 'Tasks', ->
beforeEach ->
waitsForPromise ->
atom.workspace.open().then (o) -> editor = o
waitsForPromise ->
atom.packages.activatePackage('tasks')
runs ->
grammar = atom.grammars.grammarForScopeName 'source.todo'
editor = atom.workspace.getActiveTextEditor()
editor.setGrammar grammar
nowStamp = tasksUtilities.getFormattedDate(1000)
describe 'grammar should load', ->
it 'loads', ->
expect(grammar).toBeDefined()
expect(grammar.scopeName).toBe 'source.todo'
describe 'should tokenize', ->
it 'tokenizes a task', ->
tokens = grammar.tokenizeLines('☐ text @tag(test)')
expect(tokens[0][0]).toEqual value: '☐', scopes: [baseTokens..., 'keyword.tasks.marker']
expect(tokens[0][1]).toEqual value: ' text ', scopes: baseTokens
expect(tokens[0][2]).toEqual value: '@', scopes: [baseTokens..., 'tasks.attribute.tag']
expect(tokens[0][3]).toEqual value: 'tag', scopes: [baseTokens..., 'tasks.attribute.tag', 'tasks.attribute-name']
# skip (
expect(tokens[0][5]).toEqual value: 'test', scopes: [baseTokens..., 'tasks.attribute.tag', 'tasks.attribute-value']
it 'tokenizes a project', ->
tokens = grammar.tokenizeLines('project:')
expect(tokens[0][0]).toEqual value: 'project', scopes: ['source.todo', 'control.tasks.header.project', 'control.tasks.header-title']
it 'tokenizes a completed task', ->
tokens = grammar.tokenizeLines('✔ text @done()')
expect(tokens[0][3]).toEqual value: 'done', scopes: [doneTokens..., 'tasks.attribute.done', 'tasks.attribute-name']
it 'tokenizes a cancelled task', ->
tokens = grammar.tokenizeLines('✘ text @cancelled()')
expect(tokens[0][3]).toEqual value: 'cancelled', scopes: [cancelledTokens..., 'tasks.attribute.cancelled', 'tasks.attribute-name']
describe 'manage tasks', ->
it 'creates a task below', ->
editor.setText '☐ item 1'
Tasks.newTask()
editor.insertText 'item 2'
line = editor.tokenizedBuffer.tokenizedLines[1]
expect(line.tokens[0]).toEqual value: '☐', scopes: [baseTokens..., 'keyword.tasks.marker']
expect(editor.indentationForBufferRow 1).toBe 0
it 'creates a task above', ->
editor.setText '☐ item 1'
Tasks.newTask(-1)
editor.insertText 'item 2'
line = editor.tokenizedBuffer.tokenizedLines[0]
expect(line.tokens[0]).toEqual value: '☐', scopes: [baseTokens..., 'keyword.tasks.marker']
expect(editor.indentationForBufferRow 1).toBe 0
it 'completes tasks', ->
editor.setText 'project:\n ☐ item 1'
editor.setCursorBufferPosition [1,0]
Tasks.completeTask()
line = editor.tokenizedBuffer.tokenizedLines[1]
expect(line.tokens[1]).toEqual value: '✔', scopes: [doneTokens..., 'keyword.tasks.marker']
expect(line.tokens[4]).toEqual value: 'done', scopes: [doneTokens..., 'tasks.attribute.done', 'tasks.attribute-name']
expect(line.tokens[12]).toEqual value: 'project', scopes: [doneTokens..., 'tasks.attribute.project', 'tasks.attribute-value']
it 'cancels tasks', ->
editor.setText 'project:\n ☐ item 1'
editor.setCursorBufferPosition [1,0]
Tasks.cancelTask()
line = editor.tokenizedBuffer.tokenizedLines[1]
expect(line.tokens[1]).toEqual value: '✘', scopes: [cancelledTokens..., 'keyword.tasks.marker']
expect(line.tokens[4]).toEqual value: 'cancelled', scopes: [cancelledTokens..., 'tasks.attribute.cancelled', 'tasks.attribute-name']
expect(line.tokens[12]).toEqual value: 'project', scopes: [cancelledTokens..., 'tasks.attribute.project', 'tasks.attribute-value']
it 'should add a timestamp', ->
editor.setText ' ☐ item 1'
Tasks.setTimestamp()
line = editor.tokenizedBuffer.tokenizedLines[0]
expect(line.tokens[4]).toEqual value: 'timestamp', scopes: [baseTokens..., 'tasks.attribute.timestamp', 'tasks.attribute-name']
expect(line.tokens[6]).toEqual value: nowStamp, scopes: [baseTokens..., 'tasks.attribute.timestamp', 'tasks.attribute-value']
it 'should update a timestamp', ->
editor.setText ' ✔ item 1 @done(1970-1-1 0:00)'
Tasks.setTimestamp()
line = editor.tokenizedBuffer.tokenizedLines[0]
expect(line.tokens[6]).toEqual value: nowStamp, scopes: [doneTokens..., 'tasks.attribute.done', 'tasks.attribute-value']
it 'should convert to task', ->
editor.setText 'item'
Tasks.convertToTask()
line = editor.tokenizedBuffer.tokenizedLines[0]
expect(line.tokens[0]).toEqual value: '☐', scopes: [baseTokens..., 'keyword.tasks.marker']
it 'should convert to task with timestamp', ->
atom.config.set 'tasks.addTimestampOnConvertToTask', true
editor.setText 'item'
Tasks.convertToTask()
line = editor.tokenizedBuffer.tokenizedLines[0]
expect(line.tokens[5]).toEqual value: nowStamp, scopes: [baseTokens..., 'tasks.attribute.timestamp', 'tasks.attribute-value']
it 'should archive completed tasks', ->
editor.setText('''
project:
☐ item 1
✔ item 2 @done(1970-1-1 0:00) @project(project)
''')
Tasks.tasksArchive()
line = editor.tokenizedBuffer.tokenizedLines[3]
expect(line.tokens[0]).toEqual value: '___________________', scopes: ['source.todo']
line = editor.tokenizedBuffer.tokenizedLines[4]
expect(line.tokens[0]).toEqual value: 'Archive', scopes: ['source.todo', 'control.tasks.header.archive', 'control.tasks.header-title']
line = editor.tokenizedBuffer.tokenizedLines[5]
expect(line.tokens[2]).toEqual value: ' item 2 ', scopes: doneTokens
it 'should archive cancelled tasks', ->
editor.setText('''
project:
☐ item 1
✘ item 2 @cancelled(1970-1-1 0:00) @project(project)
''')
Tasks.tasksArchive()
line = editor.tokenizedBuffer.tokenizedLines[5]
expect(line.tokens[2]).toEqual value: ' item 2 ', scopes: cancelledTokens
describe 'Taskpaper', ->
beforeEach ->
atom.config.set 'tasks.baseMarker', '-'
atom.config.set 'tasks.completeMarker', '-'
atom.config.set 'tasks.cancelledMarker', '-'
grammar = atom.grammars.grammarForScopeName 'source.todo'
editor.setGrammar grammar
describe 'should tokenize', ->
it 'tokenizes a task', ->
tokens = grammar.tokenizeLines('- text @tag(test)')
expect(tokens[0][0]).toEqual value: '-', scopes: [baseTokens..., 'keyword.tasks.marker']
expect(tokens[0][1]).toEqual value: ' text ', scopes: baseTokens
expect(tokens[0][2]).toEqual value: '@', scopes: [baseTokens..., 'tasks.attribute.tag']
expect(tokens[0][3]).toEqual value: 'tag', scopes: [baseTokens..., 'tasks.attribute.tag', 'tasks.attribute-name']
# skip (
expect(tokens[0][5]).toEqual value: 'test', scopes: [baseTokens..., 'tasks.attribute.tag', 'tasks.attribute-value']
it 'tokenizes a completed task', ->
tokens = grammar.tokenizeLines('- text @done()')
expect(tokens[0][3]).toEqual value: 'done', scopes: [doneTokens..., 'tasks.attribute.done', 'tasks.attribute-name']
it 'tokenizes a cancelled task', ->
tokens = grammar.tokenizeLines('- text @cancelled()')
expect(tokens[0][3]).toEqual value: 'cancelled', scopes: [cancelledTokens..., 'tasks.attribute.cancelled', 'tasks.attribute-name']
describe 'Complex markers', ->
beforeEach ->
atom.config.set 'tasks.baseMarker', '[ ]'
atom.config.set 'tasks.completeMarker', '[x]'
atom.config.set 'tasks.cancelledMarker', '[-]'
grammar = atom.grammars.grammarForScopeName 'source.todo'
editor.setGrammar grammar
describe 'should tokenize', ->
it 'tokenizes a task', ->
tokens = grammar.tokenizeLines('[ ] text @tag(test)')
expect(tokens[0][0]).toEqual value: '[ ]', scopes: [baseTokens..., 'keyword.tasks.marker']
expect(tokens[0][1]).toEqual value: ' text ', scopes: baseTokens
expect(tokens[0][2]).toEqual value: '@', scopes: [baseTokens..., 'tasks.attribute.tag']
expect(tokens[0][3]).toEqual value: 'tag', scopes: [baseTokens..., 'tasks.attribute.tag', 'tasks.attribute-name']
# skip (
expect(tokens[0][5]).toEqual value: 'test', scopes: [baseTokens..., 'tasks.attribute.tag', 'tasks.attribute-value']
it 'tokenizes a completed task', ->
tokens = grammar.tokenizeLines('[x] text @done()')
expect(tokens[0][3]).toEqual value: 'done', scopes: [doneTokens..., 'tasks.attribute.done', 'tasks.attribute-name']
it 'tokenizes a cancelled task', ->
tokens = grammar.tokenizeLines('[-] text @cancelled()')
expect(tokens[0][3]).toEqual value: 'cancelled', scopes: [cancelledTokens..., 'tasks.attribute.cancelled', 'tasks.attribute-name']
describe 'Escape', ->
beforeEach ->
editor.setText 'Project with (parens):\n ☐ An incomplete task'
editor.setCursorBufferPosition [1,0]
describe 'should escape tag values', ->
it 'adds a project attribute', ->
Tasks.completeTask()
projectTag = tasksUtilities.getTag editor, 1, 'project', '@'
expect(projectTag).toBeDefined()
expect(projectTag.tagValue.value).toEqual("Project with \\(parens\\)")
describe 'should discard parenthesized done tags', ->
it 'adds a project attribute', ->
Tasks.completeTask()
projectTag = tasksUtilities.getTag editor, 1, 'project', '@'
# undo completion
Tasks.completeTask()
line = editor.getBuffer().lineForRow 1
expect(line).toMatch(/☐\s+An incomplete task\s*$/)
================================================
FILE: styles/tasks.less
================================================
@import "ui-variables";
atom-text-editor.editor {
.syntax--tasks {
&.syntax--header { color: @text-color-warning; }
&.syntax--marker { color: @text-color-subtle; }
&.syntax--attribute { color: @text-color-info; }
&.syntax--done,
&.syntax--cancelled {
&.syntax--text { color: @text-color-subtle; }
.syntax--marker { color: @text-color-success; }
.syntax--attribute {
color: mix(@text-color-info, @text-color-subtle, 30%);
}
}
&.syntax--cancelled .syntax--marker { color: @text-color-error; }
}
}
gitextract_py66d33m/
├── .gitignore
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── demo.todo
├── keymaps/
│ └── tasks.cson
├── lib/
│ ├── tasks.coffee
│ ├── tasks.cson
│ ├── tasksUtilities.coffee
│ ├── touchbar.coffee
│ └── views/
│ └── task-status-view.coffee
├── menus/
│ └── tasks.cson
├── package.json
├── project.todo
├── settings/
│ └── tasks.cson
├── spec/
│ ├── benchmark.todo
│ ├── complexMarkers.todo
│ ├── sample.taskpaper
│ └── tasks-spec.coffee
└── styles/
└── tasks.less
Condensed preview — 20 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (195K chars).
[
{
"path": ".gitignore",
"chars": 47,
"preview": ".DS_Store\nnpm-debug.log\nnode_modules\ntest.todo\n"
},
{
"path": "CHANGELOG.md",
"chars": 3723,
"preview": "## 2.10.1\n* Fix bug with requiring built-in season lib as opposed to node_modules one. Fixes #93\n\n## 2.10.0\n* Fix bug wi"
},
{
"path": "LICENSE.md",
"chars": 1061,
"preview": "Copyright (c) 2014 Christopher Rolfs\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of th"
},
{
"path": "README.md",
"chars": 2073,
"preview": "## What's New in 2.0\n\n* Archiving tasks hotkey is now `cmd-shift-a`\n* Can convert non-task lines to tasks\n* Optimized pe"
},
{
"path": "demo.todo",
"chars": 293,
"preview": "☐ testing\nMy Tasks:\n ☐ Implement testing for tasks package\n ☐ Update styles @normal(tag with value) sounds good\n ✔ Cr"
},
{
"path": "keymaps/tasks.cson",
"chars": 1074,
"preview": "# Keybindings require three things to be fully defined: A selector that is\n# matched against the focused element, the ke"
},
{
"path": "lib/tasks.coffee",
"chars": 15037,
"preview": "{Point} = require 'atom'\n_ = require 'underscore'\nCSON = require 'season'\ntasks = require './tasksUtilities'\nTaskStatusV"
},
{
"path": "lib/tasks.cson",
"chars": 1149,
"preview": "'fileTypes': [\n 'todo'\n 'taskpaper'\n]\n'scopeName': 'source.todo'\n\n'name': 'Tasks'\n'patterns': [\n\n {\n 'match': '^(["
},
{
"path": "lib/tasksUtilities.coffee",
"chars": 9134,
"preview": "{Point, Range} = require 'atom'\n_ = require 'underscore'\nCSON = require 'season'\nmoment = require 'moment'\npath = requir"
},
{
"path": "lib/touchbar.coffee",
"chars": 1478,
"preview": "tasks = require './tasksUtilities'\n\n{TouchBar} = require('remote')\n{TouchBarButton, TouchBarSpacer} = TouchBar\n\nmodule.e"
},
{
"path": "lib/views/task-status-view.coffee",
"chars": 1993,
"preview": "tasks = require '../tasksUtilities'\n_ = require 'underscore'\n\nclass TaskStatusView extends HTMLElement\n initialize: ->\n"
},
{
"path": "menus/tasks.cson",
"chars": 783,
"preview": "'context-menu':\n 'atom-text-editor[data-grammar~=\"todo\"]': [\n {'type': 'separator'}\n {\n 'label': 'Add Task B"
},
{
"path": "package.json",
"chars": 560,
"preview": "{\n \"name\": \"tasks\",\n \"main\": \"./lib/tasks\",\n \"version\": \"2.10.1\",\n \"description\": \"Manage your todo lists\",\n \"keywo"
},
{
"path": "project.todo",
"chars": 2719,
"preview": "v3:\n ☐ Add more test coverage for utilities\n ☐ Export functionality as a service?\n ☐ Add pull-request to symbols view"
},
{
"path": "settings/tasks.cson",
"chars": 115,
"preview": "'.source.todo, .source.taskpaper':\n 'editor':\n 'autoIndentOnPaste': false\n 'increaseIndentPattern': '^.*:$'\n"
},
{
"path": "spec/benchmark.todo",
"chars": 137040,
"preview": "Project 0:\n ☐ test 1\n ☐ test 2\n ☐ test 3\n ☐ test 4\n ☐ test 5\n ☐ test 6\n ☐ test 7\n ☐ test 8\n ☐ test 9\n"
},
{
"path": "spec/complexMarkers.todo",
"chars": 89,
"preview": "Test:\n [ ] First task @tag1\n [ ] Second task\n plain text, non-task\n [ ] Another task\n"
},
{
"path": "spec/sample.taskpaper",
"chars": 137,
"preview": "Yard:\r\n - Rake leaves\r\n - Put away hose @tag1 and something else @tag2\r\n - Clear garden\r\nGroceries:\r\n - Milk\r\n - Eg"
},
{
"path": "spec/tasks-spec.coffee",
"chars": 10017,
"preview": "path = require 'path'\nTasks = require '../lib/tasks'\ntasksUtilities = require '../lib/tasksUtilities'\n[editor, buffer, g"
},
{
"path": "styles/tasks.less",
"chars": 562,
"preview": "@import \"ui-variables\";\n\natom-text-editor.editor {\n .syntax--tasks {\n &.syntax--header { color: @text-color-warning;"
}
]
About this extraction
This page contains the full source code of the irrationalistic/atom-tasks GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 20 files (184.7 KB), approximately 21.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.