intent 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/bin/project +10 -0
- data/lib/intent/args.rb +32 -0
- data/lib/intent/commands/intent.rb +11 -2
- data/lib/intent/commands/inventory.rb +11 -2
- data/lib/intent/commands/project.rb +91 -0
- data/lib/intent/commands/projects.rb +9 -4
- data/lib/intent/commands.rb +1 -1
- data/lib/intent/core/directory.rb +37 -0
- data/lib/intent/core/documents.rb +17 -0
- data/lib/intent/core/inbox.rb +29 -0
- data/lib/intent/core/inventory.rb +101 -0
- data/lib/intent/core/projects.rb +58 -0
- data/lib/intent/core.rb +23 -163
- data/lib/intent/desktop.rb +5 -3
- data/lib/intent/dispatcher.rb +20 -0
- data/lib/intent/env.rb +26 -0
- data/lib/intent/text/intent.help.txt +82 -0
- data/{bin/projects_active → lib/intent/ui/projects_active.rb} +0 -0
- data/lib/intent/version.rb +1 -1
- data/lib/intent.rb +20 -6
- metadata +15 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eceb2c98af31fff1168ee446ea327a674c510e96d5bcfb948cae895e391a8399
|
4
|
+
data.tar.gz: a8225ec76a08ba859b7f8abff5729527e0426e51fff1757c26e00a63f5b5a9af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7151b6b4e09485ade42fc3dc8756aeaf933d72b96acdb5d216764866d9cf52dd04cfacb828bc4f8498e2a5d90397d7db30add5ae44f3370afb0f9c5916f24765
|
7
|
+
data.tar.gz: fb6b9209b34d67417a232b68e2a02dea9faf99e822252becc5d1b7dfc5a6fad5c8885ba4050258a587abc6e7afdc366e97afaf10be0ebbb768e45f2ba014987d
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Intent
|
2
2
|
|
3
|
-
Automation engine with todo.txt
|
3
|
+
> **Automation engine with todo.txt**
|
4
4
|
|
5
5
|
This tool is mired deep in the obscurity and pedantry of the text-based computing culture that originated in the 1970s and still continues today. You probably don’t want to use this.
|
6
6
|
|
@@ -16,6 +16,10 @@ gem install intent
|
|
16
16
|
intent help
|
17
17
|
```
|
18
18
|
|
19
|
+
## The ledger concept
|
20
|
+
|
21
|
+
Docs and an essay about managing text-based computational ledgers ‘coming soon’ (eventually).
|
22
|
+
|
19
23
|
## Copyright & License
|
20
24
|
|
21
25
|
Copyright 2024 Mark Rickerby <https://maetl.net>.
|
data/bin/project
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
path = __FILE__
|
3
|
+
while File.symlink?(path)
|
4
|
+
path = File.expand_path(File.readlink(path), File.dirname(path))
|
5
|
+
end
|
6
|
+
$:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib'))
|
7
|
+
|
8
|
+
require 'intent'
|
9
|
+
|
10
|
+
Intent::Dispatcher.exec_command(:project, ARGV.dup)
|
data/lib/intent/args.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Intent
|
2
|
+
class Args
|
3
|
+
def initialize(input)
|
4
|
+
@arity = input.length
|
5
|
+
|
6
|
+
unless empty?
|
7
|
+
case @arity
|
8
|
+
when 1 then interpret_args_unary(input[0])
|
9
|
+
when 2 then interpret_args_binary(input[0], input[1])
|
10
|
+
when 3 then interpret_args_ternary(input[0], input[1], input[2])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def empty?
|
16
|
+
@arity == 0
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def interpret_args_unary(arg1)
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def interpret_args_binary(arg1, arg2)
|
26
|
+
end
|
27
|
+
|
28
|
+
def interpret_args_ternary(arg1, arg2, arg3)
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,8 +1,17 @@
|
|
1
1
|
module Intent
|
2
2
|
module Commands
|
3
|
-
class Intent
|
3
|
+
class Intent < Base
|
4
4
|
def run(args, output)
|
5
|
-
|
5
|
+
if args.empty?
|
6
|
+
print_help(output)
|
7
|
+
else
|
8
|
+
case args.first.to_sym
|
9
|
+
when :help
|
10
|
+
print_help(output)
|
11
|
+
else
|
12
|
+
raise Core::Errors::COMMAND_NOT_FOUND
|
13
|
+
end
|
14
|
+
end
|
6
15
|
end
|
7
16
|
end
|
8
17
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'tty-reader'
|
2
|
-
|
3
1
|
module Intent
|
4
2
|
module Commands
|
5
3
|
class Inventory < Base
|
@@ -28,6 +26,12 @@ module Intent
|
|
28
26
|
when :folder then assign_folder(args, output)
|
29
27
|
when :box then assign_box(args, output)
|
30
28
|
end
|
29
|
+
# CONCEPT:
|
30
|
+
# Verbs::Assign.invoke_rewrite()
|
31
|
+
# verbs.assign.invoke_rewrite(documents.inventory, noun)
|
32
|
+
when :sync then sync_inventory(args, output)
|
33
|
+
else
|
34
|
+
raise Errors:COMMAND_NOT_FOUND
|
31
35
|
end
|
32
36
|
end
|
33
37
|
end
|
@@ -205,6 +209,11 @@ module Intent
|
|
205
209
|
box.projects.concat(details[:projects])
|
206
210
|
documents.inventory.save!
|
207
211
|
end
|
212
|
+
|
213
|
+
def sync_inventory(args, output)
|
214
|
+
result = documents.inventory.sync!
|
215
|
+
output.puts "Sync inventory result: #{result}"
|
216
|
+
end
|
208
217
|
end
|
209
218
|
end
|
210
219
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Intent
|
2
|
+
module Commands
|
3
|
+
class Project < Projects
|
4
|
+
def run(args, output)
|
5
|
+
if args.empty?
|
6
|
+
print_help(output)
|
7
|
+
else
|
8
|
+
case args.first.to_sym
|
9
|
+
when :help
|
10
|
+
print_help(output)
|
11
|
+
when :link
|
12
|
+
if args[1].nil?
|
13
|
+
# launch into projects selection?
|
14
|
+
raise "Need to link to a noun at this stage, sorry"
|
15
|
+
else
|
16
|
+
case args[1].to_sym
|
17
|
+
when :notes then link_notes(args, output)
|
18
|
+
else
|
19
|
+
raise "Noun not implemented"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
raise Errors:COMMAND_NOT_FOUND
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def link_notes(args, output, needs_assign=false)
|
31
|
+
prompt = TTY::Prompt.new
|
32
|
+
|
33
|
+
project = if args.last.start_with?('+')
|
34
|
+
# args.last
|
35
|
+
# if documents.working_directory.is_linked?
|
36
|
+
# documents.working_directory.project
|
37
|
+
# else
|
38
|
+
# end
|
39
|
+
raise "Good idea and should work but not implemented properly, sorry"
|
40
|
+
else
|
41
|
+
# TODO: need to test if working_directory is documents_dir
|
42
|
+
#
|
43
|
+
if documents.working_directory.is_linked?
|
44
|
+
documents.working_directory.project
|
45
|
+
else
|
46
|
+
needs_assign = true
|
47
|
+
p_name = prompt.select('assign directory to project:', documents.projects.all_tokens)
|
48
|
+
p_id = prompt.ask('id for this directory:', default: generate_id)
|
49
|
+
p_name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if needs_assign
|
54
|
+
c_id = documents.inventory.local_computer_id
|
55
|
+
documents.projects.add_directory!(documents.working_directory.path, p_name, p_id, c_id)
|
56
|
+
end
|
57
|
+
|
58
|
+
project_ref = project.sub('+', '')
|
59
|
+
|
60
|
+
# Symlink done using maetl local notes convention, this could be improved
|
61
|
+
# and made more flexible. Would also be good to delegate this outside
|
62
|
+
# of the UI routine link_notes()
|
63
|
+
target_path = File.join(Env.documents_dir, project.sub('+', ''), 'notes.md')
|
64
|
+
|
65
|
+
if File.exist?(target_path)
|
66
|
+
# TODO: use directory instance given by input filtering so that
|
67
|
+
# operations can work on both working dir and a path provided in the UI
|
68
|
+
symbolic_path = File.join(documents.working_directory.path, 'NOTES.md')
|
69
|
+
File.symlink(target_path, symbolic_path)
|
70
|
+
|
71
|
+
# ignore_path = File.join(documents.working_directory.path, '.gitignore')
|
72
|
+
# if File.exist?(ignore_path)
|
73
|
+
# unless File.read(ignore_path).to_s.include?('NOTES.md')
|
74
|
+
# File.write(ignore_path, "NOTES.md\n", mode: 'a+')
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
else
|
78
|
+
output.puts "#{project} does not have notes"
|
79
|
+
end
|
80
|
+
|
81
|
+
# output.puts Dir.pwd
|
82
|
+
# output.puts ::Intent::Env.documents_dir
|
83
|
+
# output.puts ::Intent::Env.computer_serial
|
84
|
+
# Check if current working directory is a linked directory
|
85
|
+
#item = documents.projects.linked_directory(Dir.pwd)
|
86
|
+
#output.puts item
|
87
|
+
#File.symlink("DOCUMENT_DIR/project-name/notes.md", "Projects/project-name/NOTES.md")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'readline'
|
2
|
-
|
3
1
|
module Intent
|
4
2
|
module Commands
|
5
3
|
class Projects < Base
|
@@ -14,8 +12,10 @@ module Intent
|
|
14
12
|
documents.projects.all.each do |task|
|
15
13
|
output.puts task.highlight_as_project
|
16
14
|
end
|
17
|
-
when :add
|
18
|
-
|
15
|
+
when :add then add_project(args, output)
|
16
|
+
when :sync then sync_project(args, output)
|
17
|
+
else
|
18
|
+
raise Errors:COMMAND_NOT_FOUND
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -29,6 +29,11 @@ module Intent
|
|
29
29
|
name = "+#{name}" unless name.start_with?('+')
|
30
30
|
output.puts name
|
31
31
|
end
|
32
|
+
|
33
|
+
def sync_project(args, output)
|
34
|
+
result = documents.projects.sync!
|
35
|
+
output.puts "Sync projects result: #{result}"
|
36
|
+
end
|
32
37
|
end
|
33
38
|
end
|
34
39
|
end
|
data/lib/intent/commands.rb
CHANGED
@@ -3,7 +3,7 @@ require 'intent/commands/errors'
|
|
3
3
|
require 'intent/commands/intent'
|
4
4
|
require 'intent/commands/todo'
|
5
5
|
require 'intent/commands/projects'
|
6
|
-
|
6
|
+
require 'intent/commands/project'
|
7
7
|
#require 'intent/commands/ideas'
|
8
8
|
#require 'intent/commands/idea'
|
9
9
|
require 'intent/commands/inventory'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Intent
|
2
|
+
module Core
|
3
|
+
class Directory
|
4
|
+
attr_reader :path
|
5
|
+
|
6
|
+
def initialize(path, projects)
|
7
|
+
@path = path
|
8
|
+
@ledger = projects
|
9
|
+
@record = projects.all.find { |d| d.tags[:is] == 'directory' && d.text == @path }
|
10
|
+
end
|
11
|
+
|
12
|
+
def project
|
13
|
+
record.projects.first
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_linked?
|
17
|
+
!record.nil? && record.projects.any?
|
18
|
+
end
|
19
|
+
|
20
|
+
def assign!(project)
|
21
|
+
if record.nil?
|
22
|
+
@record = Record.new("#{Date.today} #{@path} is:directory type:#{type} sku:#{sku}")
|
23
|
+
ledger.append(record)
|
24
|
+
else
|
25
|
+
record.projects << project
|
26
|
+
end
|
27
|
+
|
28
|
+
ledger.save!
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :ledger
|
34
|
+
attr_reader :record
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Intent
|
2
|
+
module Core
|
3
|
+
class Documents
|
4
|
+
attr_reader :projects
|
5
|
+
attr_reader :inventory
|
6
|
+
attr_reader :inbox
|
7
|
+
attr_reader :working_directory
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@projects = Projects.new("#{Intent::Env.documents_dir}/projects.txt")
|
11
|
+
@inventory = Inventory.new("#{Intent::Env.documents_dir}/inventory.txt")
|
12
|
+
@inbox = Inbox.new("#{Intent::Env.documents_dir}/todo.txt")
|
13
|
+
@working_directory = Directory.new(Dir.pwd, @projects)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Intent
|
2
|
+
module Core
|
3
|
+
class Inbox
|
4
|
+
attr_reader :list
|
5
|
+
|
6
|
+
def initialize(db_path)
|
7
|
+
@list = List.new(db_path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def all
|
11
|
+
@list.by_not_done
|
12
|
+
end
|
13
|
+
|
14
|
+
def focused
|
15
|
+
@list.by_context('@focus').by_not_done
|
16
|
+
end
|
17
|
+
|
18
|
+
def focused_projects
|
19
|
+
focused.map { |t| t.projects }.flatten.uniq
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_line!(line)
|
23
|
+
record = Record.new("#{Date.today} #{line}")
|
24
|
+
@list.prepend(record)
|
25
|
+
@list.save!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Intent
|
2
|
+
module Core
|
3
|
+
class Inventory
|
4
|
+
attr_reader :list
|
5
|
+
attr_reader :ledger_path
|
6
|
+
|
7
|
+
def initialize(db_path)
|
8
|
+
@ledger_path = db_path
|
9
|
+
@list = List.new(db_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
list.by_not_done
|
14
|
+
end
|
15
|
+
|
16
|
+
def folder_by_id(id)
|
17
|
+
all.find { |i| i.tags[:is] == 'folder' && i.tags[:id] == id }
|
18
|
+
end
|
19
|
+
|
20
|
+
def folders
|
21
|
+
all.filter { |i| i.tags[:is] == 'folder' }
|
22
|
+
end
|
23
|
+
|
24
|
+
def items_in(id)
|
25
|
+
all.filter { |i| i.tags[:in] == id }
|
26
|
+
end
|
27
|
+
|
28
|
+
def unassigned_folders
|
29
|
+
all.filter { |i| i.tags[:is] == 'folder' && i.projects.empty? }
|
30
|
+
end
|
31
|
+
|
32
|
+
def assigned_folders
|
33
|
+
all.filter { |i| i.tags[:is] == 'folder' && i.projects.any? }
|
34
|
+
end
|
35
|
+
|
36
|
+
def boxes
|
37
|
+
all.filter { |i| i.tags[:is] == 'box' }
|
38
|
+
end
|
39
|
+
|
40
|
+
def unassigned_boxes
|
41
|
+
all.filter { |i| i.tags[:is] == 'box' && i.projects.empty? }
|
42
|
+
end
|
43
|
+
|
44
|
+
def assigned_boxes
|
45
|
+
all.filter { |i| i.tags[:is] == 'box' && i.projects.any? }
|
46
|
+
end
|
47
|
+
|
48
|
+
def units_of(noun)
|
49
|
+
all.filter { |i| i.tags[:is] == 'unit' && i.tags[:type] == noun.to_s }
|
50
|
+
end
|
51
|
+
|
52
|
+
def local_computer_id
|
53
|
+
all.find { |i| i.tags[:is] == 'computer' && i.tags[:serial] == Env.computer_serial }.tags[:id]
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_unit!(description, type, sku)
|
57
|
+
record = Record.new("#{Date.today} #{description} is:unit type:#{type} sku:#{sku}")
|
58
|
+
@list.append(record)
|
59
|
+
@list.save!
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_item!(description, id, type, sku, box=nil)
|
63
|
+
description << " in:#{box}" unless box.nil?
|
64
|
+
record = Record.new("#{Date.today} #{description} id:#{id} is:#{type} sku:#{sku}")
|
65
|
+
@list.append(record)
|
66
|
+
@list.save!
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_folder!(description, id, sku, box=nil)
|
70
|
+
add_item!(description, id, :folder, sku, box)
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_box!(description, id, sku)
|
74
|
+
add_item!(description, id, :box, sku)
|
75
|
+
end
|
76
|
+
|
77
|
+
def save!
|
78
|
+
@list.save!
|
79
|
+
end
|
80
|
+
|
81
|
+
def sync!
|
82
|
+
ledger_file = File.basename(ledger_path)
|
83
|
+
|
84
|
+
if repo.status.changed?(ledger_file)
|
85
|
+
repo.add(ledger_file)
|
86
|
+
repo.commit("Synchronizing inventory [#{Time.new}]")
|
87
|
+
repo.push
|
88
|
+
true # Result:OK
|
89
|
+
else
|
90
|
+
false # Result::NO_CHANGES
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def repo
|
97
|
+
@repo ||= Git.open(Env.documents_dir, :log => Logger.new(STDERR, level: Logger::INFO))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Intent
|
2
|
+
module Core
|
3
|
+
class Projects
|
4
|
+
attr_reader :list
|
5
|
+
attr_reader :ledger_path
|
6
|
+
|
7
|
+
def initialize(db_path)
|
8
|
+
@ledger_path = db_path
|
9
|
+
@list = List.new(db_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
list.by_not_done
|
14
|
+
end
|
15
|
+
|
16
|
+
def all_tokens
|
17
|
+
all.map { |item| item.projects.first }.uniq
|
18
|
+
end
|
19
|
+
|
20
|
+
def linked_directory(path)
|
21
|
+
all.find { |item| item.text == path && ['repository', 'directory'].include?(item.tags[:is]) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def sync!
|
25
|
+
ledger_file = File.basename(ledger_path)
|
26
|
+
|
27
|
+
if repo.status.changed?(ledger_file)
|
28
|
+
repo.add(ledger_file)
|
29
|
+
repo.commit("Synchronizing projects [#{Time.new}]")
|
30
|
+
repo.push
|
31
|
+
true # Result:OK
|
32
|
+
else
|
33
|
+
false # Result::NO_CHANGES
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_directory!(path, project, id, computer)
|
38
|
+
record = Record.new([
|
39
|
+
Date.today,
|
40
|
+
path,
|
41
|
+
project,
|
42
|
+
"is:directory",
|
43
|
+
"id:#{id}",
|
44
|
+
"computer:#{computer}"
|
45
|
+
].join(' '))
|
46
|
+
|
47
|
+
@list.append(record)
|
48
|
+
@list.save!
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def repo
|
54
|
+
@repo ||= Git.open(Env.documents_dir, :log => Logger.new(STDERR, level: Logger::INFO))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/intent/core.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
module Intent
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
end
|
2
|
+
module Core
|
3
|
+
List = ::Todo::List
|
4
|
+
Record = ::Todo::Task
|
6
5
|
|
7
|
-
|
8
|
-
ENV['INTENT_INBOX_DIR']
|
9
|
-
end
|
6
|
+
VERBS = [:add, :assign, :list, :link, :sync]
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
NOUNS = {
|
9
|
+
inventory: [:unit, :box, :folder, :computer],
|
10
|
+
projects: [:project, :directory, :repository],
|
11
|
+
todo: [:task]
|
12
|
+
}
|
13
|
+
|
14
|
+
class Action
|
15
|
+
attr_reader :verb
|
16
|
+
attr_reader :noun
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
def initialize(verb_sym, noun_r)
|
19
|
+
@verb = Verbs.instance_for(verb_sym)
|
20
|
+
@noun = Noun.new(noun_r.type, noun_r.label, noun_r.tags)
|
21
|
+
end
|
17
22
|
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module Core
|
21
|
-
List = ::Todo::List
|
22
|
-
Record = ::Todo::Task
|
23
23
|
|
24
24
|
class Noun
|
25
25
|
def initialize(type, label, tags)
|
@@ -35,151 +35,11 @@ module Intent
|
|
35
35
|
p tags
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
39
|
-
class Projects
|
40
|
-
attr_reader :list
|
41
|
-
|
42
|
-
def initialize(db_path)
|
43
|
-
@list = List.new(db_path)
|
44
|
-
end
|
45
|
-
|
46
|
-
def all
|
47
|
-
list.by_not_done
|
48
|
-
end
|
49
|
-
|
50
|
-
def all_tokens
|
51
|
-
all.map { |project| project.projects.first }
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class Inventory
|
56
|
-
attr_reader :list
|
57
|
-
|
58
|
-
def initialize(db_path)
|
59
|
-
@list = List.new(db_path)
|
60
|
-
end
|
61
|
-
|
62
|
-
def all
|
63
|
-
list.by_not_done
|
64
|
-
end
|
65
|
-
|
66
|
-
def folder_by_id(id)
|
67
|
-
all.find { |i| i.tags[:is] == 'folder' && i.tags[:id] == id }
|
68
|
-
end
|
69
|
-
|
70
|
-
def folders
|
71
|
-
all.filter { |i| i.tags[:is] == 'folder' }
|
72
|
-
end
|
73
|
-
|
74
|
-
def items_in(id)
|
75
|
-
all.filter { |i| i.tags[:in] == id }
|
76
|
-
end
|
77
|
-
|
78
|
-
def unassigned_folders
|
79
|
-
all.filter { |i| i.tags[:is] == 'folder' && i.projects.empty? }
|
80
|
-
end
|
81
|
-
|
82
|
-
def assigned_folders
|
83
|
-
all.filter { |i| i.tags[:is] == 'folder' && i.projects.any? }
|
84
|
-
end
|
85
|
-
|
86
|
-
def boxes
|
87
|
-
all.filter { |i| i.tags[:is] == 'box' }
|
88
|
-
end
|
89
|
-
|
90
|
-
def unassigned_boxes
|
91
|
-
all.filter { |i| i.tags[:is] == 'box' && i.projects.empty? }
|
92
|
-
end
|
93
|
-
|
94
|
-
def assigned_boxes
|
95
|
-
all.filter { |i| i.tags[:is] == 'box' && i.projects.any? }
|
96
|
-
end
|
97
|
-
|
98
|
-
def units_of(noun)
|
99
|
-
all.filter { |i| i.tags[:is] == 'unit' && i.tags[:type] == noun.to_s }
|
100
|
-
end
|
101
|
-
|
102
|
-
def add_unit!(description, type, sku)
|
103
|
-
record = Record.new("#{Date.today} #{description} is:unit type:#{type} sku:#{sku}")
|
104
|
-
@list.append(record)
|
105
|
-
@list.save!
|
106
|
-
end
|
107
|
-
|
108
|
-
def add_item!(description, id, type, sku, box=nil)
|
109
|
-
description << " in:#{box}" unless box.nil?
|
110
|
-
record = Record.new("#{Date.today} #{description} id:#{id} is:#{type} sku:#{sku}")
|
111
|
-
@list.append(record)
|
112
|
-
@list.save!
|
113
|
-
end
|
114
|
-
|
115
|
-
def add_folder!(description, id, sku, box=nil)
|
116
|
-
add_item!(description, id, :folder, sku, box)
|
117
|
-
end
|
118
|
-
|
119
|
-
def add_box!(description, id, sku)
|
120
|
-
add_item!(description, id, :box, sku)
|
121
|
-
end
|
122
|
-
|
123
|
-
def save!
|
124
|
-
@list.save!
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
class Inbox
|
129
|
-
attr_reader :list
|
130
|
-
|
131
|
-
def initialize(db_path)
|
132
|
-
@list = List.new(db_path)
|
133
|
-
end
|
134
|
-
|
135
|
-
def all
|
136
|
-
@list.by_not_done
|
137
|
-
end
|
138
|
-
|
139
|
-
def focused
|
140
|
-
@list.by_context('@focus').by_not_done
|
141
|
-
end
|
142
|
-
|
143
|
-
def focused_projects
|
144
|
-
focused.map { |t| t.projects }.flatten.uniq
|
145
|
-
end
|
146
|
-
|
147
|
-
def add_line!(line)
|
148
|
-
record = Record.new("#{Date.today} #{line}")
|
149
|
-
@list.prepend(record)
|
150
|
-
@list.save!
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class Documents
|
155
|
-
attr_reader :projects
|
156
|
-
attr_reader :inventory
|
157
|
-
attr_reader :inbox
|
158
|
-
|
159
|
-
def initialize
|
160
|
-
@projects = Projects.new("#{Intent::Env.documents_dir}/projects.txt")
|
161
|
-
@inventory = Inventory.new("#{Intent::Env.documents_dir}/inventory.txt")
|
162
|
-
@inbox = Inbox.new("#{Intent::Env.documents_dir}/todo.txt")
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
class Dispatcher
|
168
|
-
def self.exec_command(command, args, output=STDOUT)
|
169
|
-
command = init_command(command).new
|
170
|
-
command.run(args, output)
|
171
|
-
end
|
172
|
-
|
173
|
-
def self.init_command(command)
|
174
|
-
case command
|
175
|
-
when :intent then return Commands::Intent
|
176
|
-
when :inventory then return Commands::Inventory
|
177
|
-
when :projects then return Commands::Projects
|
178
|
-
when :project then return Commands::Project
|
179
|
-
when :todo then return Commands::Todo
|
180
|
-
else
|
181
|
-
raise Commands::Errors::COMMAND_NOT_FOUND
|
182
|
-
end
|
183
|
-
end
|
184
38
|
end
|
185
39
|
end
|
40
|
+
|
41
|
+
require 'intent/core/projects'
|
42
|
+
require 'intent/core/inventory'
|
43
|
+
require 'intent/core/inbox'
|
44
|
+
require 'intent/core/directory'
|
45
|
+
require 'intent/core/documents'
|
data/lib/intent/desktop.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Intent
|
2
|
+
class Dispatcher
|
3
|
+
def self.exec_command(command, args, output=STDOUT)
|
4
|
+
command = init_command(command).new
|
5
|
+
command.run(args, output)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.init_command(command)
|
9
|
+
case command
|
10
|
+
when :intent then return Commands::Intent
|
11
|
+
when :inventory then return Commands::Inventory
|
12
|
+
when :projects then return Commands::Projects
|
13
|
+
when :project then return Commands::Project
|
14
|
+
when :todo then return Commands::Todo
|
15
|
+
else
|
16
|
+
raise Commands::Errors::COMMAND_NOT_FOUND
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/intent/env.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Intent
|
2
|
+
module Env
|
3
|
+
def self.documents_dir
|
4
|
+
File.expand_path(ENV['INTENT_DOCUMENTS_DIR'] || "").to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.inbox_dir
|
8
|
+
ENV['INTENT_INBOX_DIR']
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.assets_dir
|
12
|
+
ENV['INTENT_ARCHIVE_DIR']
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.projects_dir
|
16
|
+
ENV['INTENT_PROJECTS_DIR']
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.computer_serial
|
20
|
+
# macOS: `system_profiler SPHardwareDataType`
|
21
|
+
# Win: `wmic bios get serialnumber`
|
22
|
+
# Linux: `ls /sys/devices/virtual/dmi/id`
|
23
|
+
ENV['INTENT_COMPUTER_SERIAL']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
====================================================================
|
2
|
+
Intent . Havin a blast on the command line
|
3
|
+
====================================================================
|
4
|
+
|
5
|
+
Welcome to the only task manager you will (n)ever need.
|
6
|
+
|
7
|
+
These docs are not written for a wide audience, but here’s the
|
8
|
+
essentials:
|
9
|
+
|
10
|
+
Verbs
|
11
|
+
-----
|
12
|
+
|
13
|
+
### `add [noun]`
|
14
|
+
|
15
|
+
Adds [noun] to the ledger denoted by the given command.
|
16
|
+
|
17
|
+
```
|
18
|
+
projects add
|
19
|
+
projects add project
|
20
|
+
projects add directory
|
21
|
+
projects add repository
|
22
|
+
|
23
|
+
project add
|
24
|
+
|
25
|
+
inventory add
|
26
|
+
inventory add folder
|
27
|
+
inventory add box
|
28
|
+
inventory add unit
|
29
|
+
inventory add computer
|
30
|
+
|
31
|
+
todo add
|
32
|
+
|
33
|
+
inbox add
|
34
|
+
```
|
35
|
+
|
36
|
+
### `assign [noun]`
|
37
|
+
|
38
|
+
Assigns projects, contexts, tags and associations to ap.
|
39
|
+
|
40
|
+
```
|
41
|
+
projects assign
|
42
|
+
|
43
|
+
project assign
|
44
|
+
|
45
|
+
inventory assign
|
46
|
+
```
|
47
|
+
|
48
|
+
### `list [noun]`
|
49
|
+
|
50
|
+
Lists elements in the ledger.
|
51
|
+
|
52
|
+
```
|
53
|
+
projects list
|
54
|
+
|
55
|
+
project list
|
56
|
+
|
57
|
+
inventory list
|
58
|
+
|
59
|
+
todo list
|
60
|
+
|
61
|
+
inbox list
|
62
|
+
```
|
63
|
+
|
64
|
+
### `link [noun]`
|
65
|
+
|
66
|
+
Links elements from a local directory to an assigned project.
|
67
|
+
|
68
|
+
```
|
69
|
+
project link
|
70
|
+
```
|
71
|
+
|
72
|
+
### `sync [noun]`
|
73
|
+
|
74
|
+
Synchronises changes to the Git origin.
|
75
|
+
|
76
|
+
```
|
77
|
+
projects sync
|
78
|
+
|
79
|
+
inventory sync
|
80
|
+
```
|
81
|
+
|
82
|
+
Documentation is patchy and not always up to date.
|
File without changes
|
data/lib/intent/version.rb
CHANGED
data/lib/intent.rb
CHANGED
@@ -1,23 +1,37 @@
|
|
1
1
|
#require 'random'
|
2
|
-
require '
|
2
|
+
#require 'pathname'
|
3
|
+
|
4
|
+
# Pastel still required but deprecated
|
3
5
|
require 'pastel'
|
4
6
|
require 'paint'
|
7
|
+
|
8
|
+
# CLI UI tools
|
5
9
|
require 'tty-prompt'
|
6
10
|
require 'tty-table'
|
7
11
|
require 'tty-tree'
|
12
|
+
|
13
|
+
# Identifiers
|
8
14
|
require 'nanoid'
|
15
|
+
#require 'calyx'
|
16
|
+
|
17
|
+
# Interact with git repos
|
18
|
+
require 'logger'
|
19
|
+
require 'git'
|
20
|
+
|
21
|
+
# todo.txt data structure support
|
22
|
+
require 'todo-txt'
|
9
23
|
require 'gem_ext/todo-txt'
|
10
24
|
|
11
25
|
Todo.customize do |options|
|
12
26
|
options.require_completed_on = false
|
13
27
|
end
|
14
28
|
|
29
|
+
# Intent library
|
15
30
|
require 'intent/version'
|
31
|
+
require 'intent/env'
|
32
|
+
require 'intent/args'
|
16
33
|
require 'intent/core'
|
34
|
+
#require 'intent/verbs'
|
17
35
|
require 'intent/commands'
|
18
36
|
require 'intent/ui/term_color'
|
19
|
-
|
20
|
-
# require 'intent/review'
|
21
|
-
# require 'intent/projects'
|
22
|
-
# require 'intent/desktop'
|
23
|
-
|
37
|
+
require 'intent/dispatcher'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: intent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Rickerby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: todo-txt
|
@@ -268,9 +268,9 @@ email:
|
|
268
268
|
executables:
|
269
269
|
- intent
|
270
270
|
- inventory
|
271
|
+
- project
|
271
272
|
- project_doc
|
272
273
|
- projects
|
273
|
-
- projects_active
|
274
274
|
- todo
|
275
275
|
- todo_review
|
276
276
|
extensions: []
|
@@ -283,30 +283,41 @@ files:
|
|
283
283
|
- Rakefile
|
284
284
|
- bin/intent
|
285
285
|
- bin/inventory
|
286
|
+
- bin/project
|
286
287
|
- bin/project_doc
|
287
288
|
- bin/projects
|
288
|
-
- bin/projects_active
|
289
289
|
- bin/todo
|
290
290
|
- bin/todo_review
|
291
291
|
- intent.gemspec
|
292
292
|
- lib/gem_ext/todo-txt.rb
|
293
293
|
- lib/intent.rb
|
294
|
+
- lib/intent/args.rb
|
294
295
|
- lib/intent/commands.rb
|
295
296
|
- lib/intent/commands/base.rb
|
296
297
|
- lib/intent/commands/errors.rb
|
297
298
|
- lib/intent/commands/intent.rb
|
298
299
|
- lib/intent/commands/inventory.rb
|
300
|
+
- lib/intent/commands/project.rb
|
299
301
|
- lib/intent/commands/projects.rb
|
300
302
|
- lib/intent/commands/todo.rb
|
301
303
|
- lib/intent/core.rb
|
304
|
+
- lib/intent/core/directory.rb
|
305
|
+
- lib/intent/core/documents.rb
|
306
|
+
- lib/intent/core/inbox.rb
|
307
|
+
- lib/intent/core/inventory.rb
|
308
|
+
- lib/intent/core/projects.rb
|
302
309
|
- lib/intent/desktop.rb
|
310
|
+
- lib/intent/dispatcher.rb
|
311
|
+
- lib/intent/env.rb
|
303
312
|
- lib/intent/projects.rb
|
304
313
|
- lib/intent/review.rb
|
314
|
+
- lib/intent/text/intent.help.txt
|
305
315
|
- lib/intent/text/inventory.help.txt
|
306
316
|
- lib/intent/text/project.help.txt
|
307
317
|
- lib/intent/text/projects.help.txt
|
308
318
|
- lib/intent/text/todo.help.txt
|
309
319
|
- lib/intent/todo.rb
|
320
|
+
- lib/intent/ui/projects_active.rb
|
310
321
|
- lib/intent/ui/term_color.rb
|
311
322
|
- lib/intent/ui/ttyui.rb
|
312
323
|
- lib/intent/verbs/add.rb
|